import { existsSync, statSync } from "fs";
import { dirname, resolve } from "path";
import { LocalLanguage, _defaultLanguage, Func, DefaultOptions, Mutable } from "../../common/types";
import { readFileSync } from "../../common/system";
import { stringEqual } from "../../common/util";
import { createConverter } from "./converter";
import { Diagnostic, DiagnosticMessage, errorMessages } from "../diagnostic";
import { createNodeFactory } from "./factory";
import {
    computeLineStarts,
    convertPreprocessorOperatorToEquivalentToken,
    createScanner,
    isIdentifierOrReservedWord,
    isLigalIdentifier,
    isReservedWord,
} from "./scanner";
import {
    Argument,
    ArrayDecl,
    ArrayTypeSignature,
    AssignmentExpression,
    BinaryOperatorKind,
    Binding,
    BinaryExpression,
    Block,
    Callee,
    CallExpr,
    CategoricalItemLiteral,
    CategoricalLiteral,
    ClassSignature,
    Comment,
    ComparisonPunctuationFlags,
    ConstantDeclaration,
    ConstSignature,
    DeclareModifierKind,
    DelcareKeywordKind,
    DoStat,
    EmptyExpr,
    EnumMemberSignature,
    EnumSignature,
    EventSection,
    EventSectionKind,
    DmsSectionKeywordKind,
    Expression,
    ExprStat,
    FalseLiteral,
    File,
    FileKind,
    ForEachStat,
    ForStat,
    FunctionDeclaration,
    FunctionSignature,
    GlobalSQLVariablesSection,
    Identifier,
    IfStat,
    IndexExpr,
    IndexExprIndex,
    IndexExprObject,
    InputDataSourceSection,
    InterfaceSignature,
    IterationExpr,
    JobSection,
    JumpStatement,
    KeywordToken,
    KeywordTokenKind,
    LineLocation,
    Literal,
    LiteralType,
    LocalDecls,
    LoggingSection,
    MemberExpr,
    MemberExpressionObject,
    MDMAreaName,
    MDMCategories,
    MDMCategory,
    MDMCategoryElementType,
    MDMCategoryExpression,
    MDMCellStyle,
    MDMCellStylePropertyFlags,
    MDMControlStyle,
    MDMControlStylePropertyFlags,
    MDMDbQuestions,
    MDMDbQuestionsColumn,
    MDMDbQuestionsProperties,
    MDMDocument,
    MDMField,
    MDMFieldFlags,
    MDMFontStyle,
    MDMFontStylePropertyFlags,
    MDMHierarchicalView,
    MDMLabel,
    MDMLabeledObject,
    MDMLabelTypeFlags,
    MDMMultiplier,
    MDMOther,
    MDMProperties,
    MDMProperty,
    MetadataSection,
    MDMSortOrder,
    MDMStyle,
    MDMPropertyFlags,
    MDMSublist,
    MDMTemplate,
    MDMTemplates,
    MDMUsageType,
    MDMUsageTypeFlags,
    MDMUserContextFlags,
    MDMValueRange,
    ModifierToken,
    ModuleSignature,
    Node,
    NodeArray,
    NullLiteral,
    NumberLiteral,
    ObjectCollectionIterator,
    OptionFlag,
    OptionSettingKeyword,
    OptionStatement,
    OutputDataSourceSection,
    ParameterSignature,
    PrecedureCanExit,
    Preprocessor,
    PPDefine,
    PPError,
    PPIf,
    PPInclude,
    PPLine,
    PPUndef,
    PropertySignature,
    Punctuation,
    PunctuationKind,
    ReadonlyTextRange,
    SectionStat,
    SelectCaseClause,
    SelectCaseComparison,
    SelectCaseCondition,
    SelectStat,
    Signature,
    SignatureKind,
    SourceFile,
    Statement,
    StringLiteral,
    SyntaxKind,
    Token,
    TokenFlags,
    TrueLiteral,
    UnaryExpr,
    UnaryOperatorKind,
    VariableDecl,
    WhileStat,
    WithStat,
    ParserContextState,
    ParserContext,
    ParserContextHandler,
    ParserState,
    MDMKeycode,
    MDMFactor,
    ParserContextStateNode,
    Section,
    SearchProgramFileCallback,
    CommentType,
    MDMClass,
    MDMPage,
    ResumeStatement,
    PPIfDef,
    PPIfNDef,
    RoutingSection,
    GenerateFileExtens,
    MutableNodeArray,
    MDMFieldTokenKind,
    MDMDeclarationKind,
    MDMDeclarationValueLike,
    MDMCodes,
    FileDirective,
    ResolveMacroParams,
    PPDefineStringizer,
    PPDefineTokenPaster,
    ParameterMacroArgument,
    ParameterMacroCallExpr,
    ScannerContextType,
    MacroExpandToken,
    MacroExpandMapping,
    PPDefineParameter,
    MacroExpandResult,
} from "./types";
import {
    getEventSectionFlag,
    getOperatorPrecedence,
    isBinaryOperatorToken,
    isCommentMetadataFileFlag,
    getCommentReferenceChild,
    isCommentScriptDmsFileFlag,
    isCommentScriptIgnoreTypeError,
    isCommentScriptMrsFileFlag,
    isDiagnosticMessage,
    isLiteralToken,
    isMetadataFieldToken,
    isNode,
    isPreprocessorOperatorToken,
    isPunctuationToken,
    normalizeLineFeedCharacter,
    removeStringQuotation,
    setTextRangeStartEnd,
    stringToLabelType,
    stringToMetadataCellStylePropertyFlag,
    stringToMetadataControlStylePropertyFlag,
    stringToMetadataFontStylePropertyFlag,
    stringToMetadataStylePropertyFlag,
    stringToMetadataUsageTypeFlag,
    stringToUserContext,
    testCellStylePropertyValue,
    testControlStylePropertyValue,
    testFontStylePropertyValue,
    testStylePropertyValue,
    tokenToString,
    getCommentReference,
} from "./util";

const factory = createNodeFactory();
const converter = createConverter(factory);

/**
 * 脚本解析器，为了避免重复实例化，此处使用了一组静态函数进行处理。
 * 解析器方法只处理 文本 -> 语法树 这个步骤，最终只返回 SourceFile
 * 对象，后续步骤由其他类来处理。
 */
export namespace Parser {

    function createParserContextHandler(): ParserContextHandler {

        let state: ParserContextState = {
            frozen: false,
            currentFrozenContext: ParserContext.none,
            frozenContexts: [],
            currentContext: ParserContext.none,
            contexts: []
        };

        return {
            current,
            currentContextNode,
            once,
            push,
            remove,
            getContextNode,
            test,
            count,
            clear,
            freeze,
            unfreeze,
            saveState,
            recoveryState,
        };

        function freeze() {
            if (state.frozenContexts.length > 0) {
                state.frozenContexts = [];
            }
            state.currentFrozenContext = state.currentContext;
            state.frozen = true;
        }

        function unfreeze() {
            if (state.frozenContexts.length > 0) {
                state.frozenContexts = [];
            }
            state.currentFrozenContext = ParserContext.none;
            state.frozen = false;
        }

        function test(context: ParserContext): boolean {
            return state.frozen ? !!(context & state.currentFrozenContext) : !!(context & state.currentContext);
        }

        function count(context: ParserContext): number {
            let result: number = 0;
            (state.frozen ? state.frozenContexts : state.contexts).forEach(item => {
                if (!!(item.context & context)) {
                    result++;
                }
            });
            return result;
        }

        function push(context: ParserContext, node?: Statement | Expression): void {
            if (state.frozen) {
                state.currentFrozenContext |= context;
                state.frozenContexts.push({ context, node });
                return;
            }
            state.currentContext |= context;
            state.contexts.push({ context, node });
        }

        function once<T>(context: ParserContext, callback: () => T): T {
            let savedState = saveState();
            push(context);
            let result = callback();
            recoveryState(savedState);
            return result;
        }

        function removeArrayItem<T>(array: T[], precidate: (element: T) => boolean): T | undefined {
            let index = array.length - 1;
            while (index >= 0) {
                if (precidate(array[index])) {
                    break;
                }
                index--;
            }
            if (index >= 0) {
                const item = array[index];
                array.splice(index, 1);
                return item;
            }
            return undefined;
        }

        function updateCurrentContext(contexts: ParserContextStateNode[]) {
            let result: ParserContext = ParserContext.none;
            for (const context of contexts) {
                result |= context.context;
            }
            return result;
        }

        function remove(context: ParserContext): void {
            if (state.frozen) {
                removeArrayItem(state.frozenContexts, element => (element.context & context) > 0);
                state.currentFrozenContext = updateCurrentContext(state.frozenContexts);
                return;
            }
            removeArrayItem(state.contexts, element => (element.context & context) > 0);
            state.currentContext = updateCurrentContext(state.contexts);
        }

        function current(): ParserContext {
            return state.frozen ? state.currentFrozenContext : state.currentContext;
        }

        function currentContextNode(): Statement | Expression | undefined {
            return state.frozen ? (state.frozenContexts.length > 0 ? state.frozenContexts[state.frozenContexts.length - 1].node : undefined) :
            state.contexts.length > 0 ? state.contexts[state.contexts.length - 1].node : undefined;
        }

        function getContextNode(context: ParserContext): Statement | Expression | undefined {
            let list = state.frozen ? state.frozenContexts : state.contexts;
            let len = list.length;
            if (len > 0) {
                for (let index = len - 1; index >= 0; index--) {
                    const element = list[index];
                    if ((context & element.context) > 0) {
                        return element.node;
                    }
                }
            }
            return undefined;
        }

        function clear() {
            if (state.frozen) {
                state.currentFrozenContext = ParserContext.none;
                state.frozenContexts.splice(0);
                return;
            }
            state.currentContext = ParserContext.none;
            state.contexts.splice(0);
        }

        function saveState(): ParserContextState {
            const frozenContexts = state.frozenContexts.map(s => Object.assign({}, s));
            const contexts = state.contexts.map(s => Object.assign({}, s));
            return {
                frozen: state.frozen,
                currentFrozenContext: state.currentContext,
                frozenContexts,
                currentContext: state.currentContext,
                contexts,
            };
        }

        function recoveryState(savedState: ParserContextState): void {
            state = savedState;
        }

    }

    const scanner = createScanner();
    const contextHandler = createParserContextHandler();

    let parsingDiagnostics: Diagnostic[] = [];

    let sourceFileName: string = "";
    let sourceFileText: string = "";
    let fileFlag: FileKind = FileKind.none;
    let nodeCount: number = 0;
    let preprocessorNodeCount: number = 0;
    let identifierCount: number = 0;

    let optionSettingNode: OptionStatement | undefined;
    let optionFlag: OptionFlag = OptionFlag.explicit;

    let currentToken: SyntaxKind = SyntaxKind.eof;
    let originIdentifiers = new Map<string, string>();

    let comments: Comment[] = [];
    let locations: LineLocation[] = [];

    let signatures: Signature<SignatureKind>[] = [];
    let declarations: FunctionDeclaration[] = [];
    let globalLocations: LineLocation[] = [];
    let references: SourceFile[] = [];
    let includeNodes: PPInclude[] = [];
    let sectionNodes: Section[] = [];
    let identifiers: Identifier[] = [];

    let preProDefineNodeMap: Map<string, PPDefine> = new Map();
    let macroExpandNodes: MacroExpandToken[] = [];
    let macroExpandIndex: number = -1;

    let isLookAhead: boolean = false;
    let resolveIncludeIdentifier: Func<string, string> | undefined;
    let searchProgramFile: SearchProgramFileCallback | undefined;
    let resolveMacroInvokeNodeStack: Func<ResolveMacroParams, void>[] = [];
    let macroNodes: Identifier[] = [];

    function initializeState(fileName?: string, initialText?: string, start?: number, sourceFileFlag?: FileKind, clearContextState?: boolean, clearExpander = true): void {
        sourceFileName = fileName ?? "";
        fileFlag = sourceFileFlag ?? (fileName ? getFileFlagFromName(fileName) : FileKind.none);
        sourceFileText = initialText ?? "";
        nodeCount = 0;
        preprocessorNodeCount = 0;
        identifierCount = 0;
        optionFlag = OptionFlag.explicit;
        optionSettingNode = undefined;
        scanner.setText(sourceFileText, start, initialText ? initialText.length : 0);
        scanner.onError(d => parsingDiagnostics.push(d));
        if (clearContextState) {
            contextHandler.clear();
        }
        // 考虑到可能调用saveState保存当前状态, 此处创建新的对象, 而不是调用Clear方法
        originIdentifiers = new Map<string, string>();
        parsingDiagnostics = [];
        currentToken = SyntaxKind.eof;
        signatures = [];
        declarations = [];
        identifiers = [];
        globalLocations = [];
        references = [];
        includeNodes = [];
        sectionNodes = [];
        comments = [];
        locations = [];
        if (clearExpander) {
            preProDefineNodeMap.clear();
            macroExpandNodes = [];
            macroExpandIndex = -1;
        }
        macroNodes = [];
    }

    export function clearState() {
        sourceFileName = "";
        sourceFileText = "";
        fileFlag = FileKind.none;
        currentToken = SyntaxKind.eof;
        nodeCount = 0;
        preprocessorNodeCount = 0;
        identifierCount = 0;
        optionFlag = OptionFlag.explicit;
        optionSettingNode = undefined;
        parsingDiagnostics = [];
        scanner.setText("");
        scanner.onError();
        contextHandler.clear();
        originIdentifiers.clear();
        signatures = [];
        declarations = [];
        identifiers = [];
        globalLocations = [];
        references = [];
        includeNodes = [];
        sectionNodes = [];
        comments = [];
        preProDefineNodeMap = new Map();
        macroExpandNodes = [];
        macroExpandIndex = -1;
        resolveMacroInvokeNodeStack = [];
        macroNodes = [];
    }

    function saveState(): ParserState {
        return {
            scannerState: scanner.saveState(),
            contextState: contextHandler.saveState(),
            parserDiagnostics: parsingDiagnostics,
            sourceFileName,
            sourceFileText,
            fileFlag,
            nodeCount,
            preprocessorNodeCount,
            identifierCount,
            optionFlag,
            optionSettingNode,
            currentToken,
            originIdentifiers,
            signatures,
            declarations,
            identifiers,
            globalLocations,
            references,
            includeNodes,
            sectionNodes,
            comments,
            resolveMacroInvokeNodeStack,
            macroNodes,
            macroExpandNodes,
            macroExpandIndex,
        };
    }

    function recoveryState(savedState: ParserState): void {
        scanner.recoveryState(savedState.scannerState);
        contextHandler.recoveryState(savedState.contextState);
        parsingDiagnostics = savedState.parserDiagnostics;
        sourceFileName = savedState.sourceFileName;
        sourceFileText = savedState.sourceFileText;
        fileFlag = savedState.fileFlag;
        nodeCount = savedState.nodeCount;
        preprocessorNodeCount = savedState.preprocessorNodeCount;
        identifierCount = savedState.identifierCount;
        optionFlag = savedState.optionFlag;
        optionSettingNode = savedState.optionSettingNode;
        currentToken = savedState.currentToken;
        originIdentifiers = savedState.originIdentifiers;
        signatures = savedState.signatures;
        declarations = savedState.declarations;
        identifiers = savedState.identifiers;
        globalLocations = savedState.globalLocations;
        references = savedState.references;
        includeNodes = savedState.includeNodes;
        sectionNodes = savedState.sectionNodes;
        comments = savedState.comments;
        resolveMacroInvokeNodeStack = savedState.resolveMacroInvokeNodeStack;
        macroNodes = savedState.macroNodes;
        macroExpandNodes = savedState.macroExpandNodes;
        macroExpandIndex = savedState.macroExpandIndex;
    }

    export function onResolveIncludeIdentifier(handler?: Func<string, string>) {
        resolveIncludeIdentifier = handler;
    }

    export function onSearchProgramFile(handler?: Func<string, File | undefined>) {
        searchProgramFile = handler;
    }

    const expandFailureResult: MacroExpandResult = { nodes: [], failure: true };

    /**
     * 扩展指定宏, 如果遇到错误, 将返回空列表。
     * 此函数会一次性扩展到最终结果, 即, 如果出现定义的套用或者将宏传入参数宏的参数,
     * 将递归调用此函数直到没有宏定义。
     *
     * @param macro
     * @param invokeNode
     * @param parameters
     * @returns
     */
    function expandMacro(macro: PPDefine, invokeNode: Identifier | ParameterMacroCallExpr, ...parameters: ParameterMacroArgument[]): MacroExpandResult {
        const nodes: MacroExpandToken[] =[];
        // 扩展错误
        let expandError: Diagnostic[] = [];
        // 需要检查是否是当前文件中的定义
        let inCurrentFile = !macro.getSourceFile();
        // 参数宏参数
        let parameterMap: Map<string, ParameterMacroArgument> = new Map();
        // 可变参数
        let varArgs: Node[] = [];
        let hasVarArg: boolean = false;
        let parameterError: boolean = false;
        if (macro.parameters) {
            for (let i = 0; i < parameters.length; i++) {
                if (i >= macro.parameters.length) {
                    if (!hasVarArg) {
                        raise(
                            errorMessages.expectNumberOfArguments,
                            invokeNode,
                            invokeNode.isIdentifier() ? invokeNode.text : invokeNode.callee.text,
                            macro.parameters.length.toString(),
                            parameters.length.toString(),
                        );
                        return expandFailureResult;
                    }
                    else {
                        varArgs.push(...parameters[i]);
                    }
                }
                else {
                    const arg = parameters[i];
                    const param = macro.parameters[i];
                    // ...
                    if (param.dotDotDot) {
                        hasVarArg = true;
                        varArgs.push(...arg);
                        continue;
                    }
                    // #identifier
                    if (param.isStringizer) {
                        for (const element of arg) {
                            if (element.isStringLiteral()) {
                                parameterError = true;
                                raise(
                                    errorMessages.stringizerTypeError,
                                    element
                                );
                            }
                        }
                        if (parameterError) {
                            return expandFailureResult;
                        }
                    }
                    parameterMap.set(param.name.text, arg);
                }
            }
        }

        /**
         * 读取指定索引的定义内容, 并添加进节点函数返回的列表, 最终将返回下一个索引, 如果遇到错误, 将返回 -1。
         *
         * @param definitions
         * @param index
         * @param invokerRange
         * @returns
         */
        function readDefinitionElement(definitions: readonly Node[], index: number, invokerRange?: MacroExpandMapping): number {
            let element = definitions[index];
            if (element.isIdentifier()) {
                // 参数宏参数
                let param: ParameterMacroArgument | undefined;
                if (parameterMap && (param = parameterMap.get(element.text))) {
                    let i = 0;
                    while (i < param.length) {
                        i = readDefinitionElement(param, i);
                        if (i === -1) {
                            return - 1;
                        }
                    }
                    return ++index;
                }
                let preDefine = preProDefineNodeMap.get(element.text);
                // 非参数宏
                if (preDefine && !preDefine.parameters) {
                    let expandResult = expandMacro(preDefine, element);
                    if (expandResult.failure) {
                        return -1;
                    }
                    nodes.push(...expandResult.nodes);
                    return ++index;
                }
                // 参数宏, 参数宏调用是否正确在解析 `invokeNode` 时已经确认,
                // 执行到此处时, 已经确定调用是正确的
                if (preDefine && preDefine.parameters) {
                    const paramStart = index + 1;
                    let correct = true;
                    // 检查是否正常调用
                    if (paramStart < definitions.length - 1 &&
                        definitions[paramStart].kind === SyntaxKind.openParenthesis
                    ) {
                        let checkIndex = paramStart + 1;
                        let parameterNodes: Node[] = [];
                        while (checkIndex < definitions.length) {
                        }
                    }
                    else {

                    }
                }
            }
            // Stringizer 和 TokenPaster 在 PreprocessorDefineStatement 解析时已经进行过核对
            // 此处不报错
            else if (element.is<PPDefineStringizer>(SyntaxKind.ppDefineStringizer)) {
                let parameterValue = parameterMap?.get(element.name.text);
                if (parameterValue) {
                    let stringLiteral = factory.createStringLiteral(parameterValue.text, LiteralType.singleLineString);
                    let node = finishNode(stringLiteral, parameterValue.start, parameterValue.end);
                    nodes.push({
                        token: node,
                        sourceMapping: {
                            start: parameterValue.start,
                            end: parameterValue.end,
                            inCurrentFile: true,
                        }
                    });
                }
                return ++index;
            }
            else if (element.is<PPDefineTokenPaster>(SyntaxKind.ppDefineTokenPaster)) {
                let text = "";
                for (const id of element.identifiers) {
                    let parameterValue = parameterMap?.get(id.text);
                    text += parameterValue ? parameterValue.text : id.text;
                }
                if (!isLigalIdentifier(text)) {
                    raise(
                        errorMessages.tokenPasterResultError,
                        invokeNode,
                        text,
                    );
                    return -1;
                }
                return ++index;
            }

            nodes.push({
                token: element,
                sourceMapping: {
                    start: invokerRange ? invokerRange.start : element.start,
                    end: invokerRange ? invokerRange.end : element.end,
                    inCurrentFile: invokerRange ? invokerRange.inCurrentFile : true,
                }
            });

            return ++index;
        }

        if (macro.definition && macro.definition.length > 0) {
            let sourceMapping: MacroExpandMapping = {
                start: invokeNode.start,
                end: invokeNode.end,
                inCurrentFile,
            };
            for (let i = 0; i < macro.definition.length; i++) {
                const node = macro.definition[i];
                if (!node.isIdentifier()) {
                    nodes.push({
                        token: node,
                        sourceMapping
                    });
                    continue;
                }
                // 参数宏的参数, 需要映射到原始位置
                const param = parameterMap.get(node.text);
                if (param) {
                    for (let j = 0; j < param.length; j++) {
                        const p = param[j];
                        if (!p.isIdentifier()) {
                            nodes.push({
                                token: p,
                                sourceMapping: {
                                    start: p.start,
                                    end: p.end,
                                    inCurrentFile: true,
                                }
                            });
                            continue;
                        }
                    }
                    continue;
                }
                nodes.push({
                    token: node,
                    sourceMapping
                });
            }
        }
        return { nodes, failure: false };
    }

    function parseScriptBase(fileName?: string, initialText?: string, start?: number, sourceFileFlag?: FileKind, clearContextState = false, clearExpander = false): SourceFile {
        initializeState(fileName, initialText, start, sourceFileFlag, clearContextState, clearExpander);
        next();
        // 检查文件头部注释信息
        const headComments = scanner.getComments();
        let commentFlag = CommentType.none;
        let commentReferenceNodes: PPInclude[] = [];
        for (const comment of headComments) {
            // 跳过块注释
            if (comment.comments.length > 1) {
                continue;
            }
            let commentText = comment.comments[0];
            let start = comment.start;
            if (isCommentMetadataFileFlag(commentText)) {
                fileFlag = FileKind.mdd;
            }
            else if (isCommentScriptMrsFileFlag(commentText)) {
                fileFlag = FileKind.mrs;
            }
            else if (isCommentScriptDmsFileFlag(commentText)) {
                fileFlag = FileKind.dms;
            }
            else if (isCommentScriptIgnoreTypeError(commentText)) {
                commentFlag |= CommentType.ignoreTypeError;
            }
            let ref = getCommentReferenceChild(commentText);
            if (ref) {
                let index = commentText.indexOf(ref);
                let resolvedPath = resolve(dirname(sourceFileName), ref);
                let file = trySearchProgramFile(resolvedPath);
                if (!file || !file.getParent(f => stringEqual(f.path, resolvedPath))) {
                    commentReferenceNodes.push(parseCommentReferenceFile(ref, start + index, start + index + ref.length, resolvedPath, file));
                }
            }
        }

        let metadata: MDMDocument | undefined;
        const statements: Statement[] = [];

        resolveMacroInvokeNodeStack.push(params => {
            macroNodes.push(params.node);
            if (params.node.isIdentifier()) {
                identifiers.push(params.node);
            }
        });

        if (fileFlag === FileKind.mdd) {
            if (match(SyntaxKind.metadataKeyword) && lookAhead(nextTokenIsOpenParenthesis)) {
                includeNodes.push(...commentReferenceNodes);
                const metadataSection = parseMetadataSection();
                statements.push(metadataSection);
                metadata = metadataSection.document;
            }
            else {
                metadata = parseMetadataDocument(_defaultLanguage, MDMUserContextFlags.analysis, MDMLabelTypeFlags.label, commentReferenceNodes);
            }
        }
        else {
            includeNodes.push(...commentReferenceNodes);
            while (true) {
                if (match(SyntaxKind.eof)) {
                    break;
                }
                const stat = parseStatement();
                statements.push(stat);
            }
        }

        const sourceFile = createSourceFileNode(sourceFileName, statements, parseTokenNode<Token<SyntaxKind.eof>>(), fileFlag, metadata);
        macroNodes.forEach(node => node.asParent(sourceFile));
        sourceFile.macroNodes = factory.createNodeArray(macroNodes);
        sourceFile.references = references;
        sourceFile.includes = includeNodes;
        sourceFile.sections = sectionNodes;
        sourceFile.commentFlag = commentFlag;
        resolveMacroInvokeNodeStack.pop();
        return sourceFile;
    }

    export function parse(fileName?: string, initialText?: string, start?: number, sourceFileFlag?: FileKind): SourceFile {
        return parseScriptBase(fileName, initialText, start, sourceFileFlag, true, true);
    }

    export function parseDeclareScripts(files: readonly { path: string, content: string }[]): SourceFile[] {
        const sourceFiles: SourceFile[] = [];
        for (const file of files) {
            const fileFlag = getFileFlagFromName(file.path);
            if (fileFlag === FileKind.declare) {
                initializeState(file.path, file.content, 0, getFileFlagFromName(file.path));
                next();
                const statements: Statement[] = [];
                while (true) {
                    if (match(SyntaxKind.eof)) {
                        break;
                    }
                    statements.push(parseStatement());
                }
                const sourceFile = createSourceFileNode(sourceFileName, statements, parseTokenNode<Token<SyntaxKind.eof>>(), fileFlag);
                sourceFiles.push(sourceFile);
            }
        }
        return sourceFiles;
    }

    function raise(message: DiagnosticMessage, ...params: string[]): void;
    function raise(message: DiagnosticMessage, node: Node, ...params: string[]): void;
    function raise(message: DiagnosticMessage, start: number, end: number, ...params: string[]): void;
    function raise(message: DiagnosticMessage, param1: number | string | ReadonlyTextRange | undefined, param2: number | string | undefined, ...params: string[]): void {

        let start: number = getNodeStart();
        let end: number = getTextPos();
        let parameters: string[] = [];
        let messageText = message.template;

        if (typeof param1 === 'string') {
            parameters.push(param1);
        } else if (typeof param1 === 'number') {
            start = param1;
        } else if (isNode(param1)) {
            start = param1.start;
            end = param1.end;
        }

        if (typeof param2 === 'string') {
            parameters.push(param2);
        } else if (typeof param2 === 'number') {
            end = param2;
        }

        if (params) {
            parameters.push(...params);
            parameters.forEach((v, i) => messageText = messageText.replace("{" + i.toString() + "}", v));
        }

        let diagnostic: Diagnostic = {
            flag: message.flag,
            code: message.code,
            start,
            length: end - start,
            message: messageText,
        };

        parsingDiagnostics.push(diagnostic);
    }

    function countNode<T extends Node>(node: Mutable<T>): T {
        if (node.isPreprocessor()) {
            preprocessorNodeCount++;
        }
        else {
            nodeCount++;
        }
        node.id = nodeCount;
        return node;
    }

    function getParsingDiagnostics(): Diagnostic[] {
        return parsingDiagnostics;
    }

    function getFileFlagFromName(fileName: string): FileKind {
        let lowerName = fileName.toLowerCase().trim();
        if (lowerName.endsWith(GenerateFileExtens.routing)) {
            return FileKind.routing;
        }
        else if (lowerName.length > 4) {
            let exten = lowerName.substring(lowerName.length - 4);
            switch (exten) {
                case ".dms":
                    return FileKind.dms;
                case ".mrs":
                    if (lowerName.length > 6 && lowerName.substring(lowerName.length - 6) === ".d.mrs") {
                        return FileKind.declare;
                    }
                    return FileKind.mrs;
                case ".ini":
                    return FileKind.ini;
                case ".bat":
                    return FileKind.bat;
                case ".mdd":
                    return FileKind.mdd;
            }
        }
        return FileKind.none;
    }

    function trySearchProgramFile(path: string) {
        if (searchProgramFile) {
            return searchProgramFile(path);
        }
    }

    function createSourceFileNode(fileName: string, statements: readonly Statement[], eof: Token<SyntaxKind.eof>, fileFlag: FileKind, metadata?: MDMDocument): Mutable<SourceFile> {
        let sourceFile = factory.createSourceFileNode(fileName, statements, eof, fileFlag) as Mutable<SourceFile>;
        setTextRangeStartEnd(sourceFile, 0, sourceFileText.length);
        sourceFile.text = sourceFileText;
        sourceFile.lineMap = computeLineStarts(sourceFileText);
        sourceFile.declarations = declarations.slice();
        sourceFile.signatures = signatures.slice();
        sourceFile.diagnostics = getParsingDiagnostics();
        sourceFile.identifiers = identifiers;
        sourceFile.metadata = metadata;
        sourceFile.comments = comments;
        sourceFile.locations.nodes.push(...locations);
        sourceFile.asChildren(metadata);
        return sourceFile;
    }

    function tryResolveMacroIdentifier(param: ResolveMacroParams) {
        if (isLookAhead) {
            return;
        }
        let length = resolveMacroInvokeNodeStack.length;
        if (length > 0) {
            resolveMacroInvokeNodeStack[length - 1](param);
        }
    }

    //
    // 此处需要注意，对于不同的上下文情况，需要进行不同的处理：
    // + 在宏名或者参数宏参数内容上下文时，不考虑宏扩展
    // + 在其他上下文情况下，优先考虑宏扩展内容
    //
    function next(): SyntaxKind {

        let nextToken = currentToken = scanner.scan();
        let aheadComments = scanner.getComments();

        if (aheadComments.length > 0) {
            comments.push(...aheadComments);
        }

        return nextToken;
    }

    function nextAnd<T>(callback: () => T): T {
        next();
        return callback();
    }

    function nextIs(flag: SyntaxKind): boolean {
        return nextAnd(() => !hasPrecedingLinebreak() && match(flag));
    }

    function nextTokenIsDot(): boolean {
        return nextIs(SyntaxKind.dot);
    }

    function nextTokenIsOpenBracket(): boolean {
        return nextIs(SyntaxKind.openBracket);
    }

    function nextTokenIsOpenParenthesis(): boolean {
        return nextIs(SyntaxKind.openParenthesis);
    }

    function nextIsAllowLinebreak(flag: SyntaxKind) {
        return nextAnd(() => match(flag));
    }

    function nextTokenIsOpenBracketaAllowLinebreak(): boolean {
        return nextIsAllowLinebreak(SyntaxKind.openBracket);
    }

    function nextTokenIsEqualAllowLinebreak(): boolean {
        return nextIsAllowLinebreak(SyntaxKind.equal);
    }

    function nextTokenIsColonAllowLinebreak(): boolean {
        return nextIsAllowLinebreak(SyntaxKind.colon);
    }

    function match(flag: SyntaxKind, allowPrecedingLinebreak: boolean = true): boolean  {
        if (!allowPrecedingLinebreak && hasPrecedingLinebreak()) {
            return false;
        }
        return currentToken === flag;
    }

    function matchOne(flags: readonly SyntaxKind[]): boolean  {
        let result = false;
        for (const flag of flags) {
            if (currentToken === flag) {
                result = true;
                break;
            }
        }
        return result;
    }

    function isPreprocessorContext(): boolean {
        return contextHandler.test(ParserContext.preprocessor);
    }

    //
    // 在触发宏扩展(MacroExpander)时, 只将SyntaxFlag映射到宏定义中,
    // 对应的扫描位置应当固定在当前的宏调用位置, 直到宏扩展结束。
    //

    function getStartPos(): number {
        return scanner.getStartPos();
    }

    function getNodeStart(): number {
        return scanner.getTokenStart();
    }

    function getTextPos(): number {
        return scanner.getTextPos();
    }

    function getTokenText(start?: number, end?: number): string {
        return normalizeLineFeedCharacter(start !== undefined ?
            scanner.getTokenText(start, end) :
            scanner.getTokenText());
    }

    function getAheadComments(startPos: number): Comment[] {
        let comments: Comment[] = [];
        let ahead = scanner.getComments();
        if (ahead.length > 0) {
            let last = ahead[ahead.length - 1];
            let aheadLine = computeLineStarts(sourceFileText.slice(last.end, startPos));
            if (aheadLine.length > 2) {
                return comments;
            }
            for (let i = ahead.length - 1; i >= 0; i--) {
                if (comments.length === 0) {
                    comments.push(ahead[i]);
                }
                else {
                    if (last.start - ahead[i].end <= 2) {
                        comments.push(ahead[i]);
                        last = ahead[i];
                    }
                    else {
                        break;
                    }
                }
            }
        }
        return comments;
    }

    function finishNode<T extends Node>(node: T, start: number, end?: number): T {
        setTextRangeStartEnd(node, start, end ?? getStartPos());
        (node as Mutable<T>).optionFlag = optionFlag;
        (node as Mutable<T>).optionNode = optionSettingNode;
        let text = getTokenText(start, end ?? getStartPos());
        if (node.isStringLiteral()) {
            (node as Mutable<Node>).text = removeStringQuotation(text);
        }
        else {
            (node as Mutable<Node>).text = normalizeLineFeedCharacter(text);
        }
        countNode(node);
        return node;
    }

    function parseTokenNode<T extends Node>(): T {
        const start = getNodeStart();
        const flag = currentToken;
        const node = factory.createNode(flag);
        next();
        return finishNode(node, start, getStartPos()) as T;
    }

    function parseOptional(flag: SyntaxKind, checkKeyword: boolean = false, requireSingleLine: boolean = false): boolean {
        if (currentToken === flag) {
            if (checkKeyword && scanner.isDelcareReservedWord()) {
                raise(errorMessages.keywordCanOnlyUseInDeclareFile, tokenToString(flag));
            }
            if (requireSingleLine && hasPrecedingLinebreak()) {
                raise(errorMessages.lostExpressionLineFeed, getStartPos(), getStartPos() + 1);
            }
            next();
            return true;
        }
        return false;
    }

    function parseOptionalToken<T extends SyntaxKind>(flag: T): Token<T> | undefined {
        if (currentToken === flag) {
            return parseTokenNode<Token<T>>();
        }
        return undefined;
    }

    function requirePrecedingLinebreak<T>(parse: () => T): T {
        if (!(scanner.atFirstLine() || hasPrecedingLinebreak())) {
            raise(errorMessages.requireLineFeed);
        }
        return parse();
    }

    function disallowPrecedingLinebreak<T>(parse: () => T): T {
        if (scanner.atBegining() || hasPrecedingLinebreak()) {
            raise(errorMessages.lostExpressionLineFeed, getStartPos(), getStartPos());
        }
        return parse();
    }

    function disallowPrecedingLinebreakNode<T extends Node>(parse: () => T, flag: T["kind"], errorText: string): T {
        if (scanner.atFirstLine() || hasPrecedingLinebreak()) {
            return createMissingNode(flag, true, errorMessages.unexpectedToken, errorText);
        }
        return parse();
    }

    function parseKeywords(keywords: { keyword: (KeywordTokenKind | DelcareKeywordKind | DmsSectionKeywordKind), declare: boolean }[]) {
        if (keywords.length === 0) {
            return;
        }
        requirePrecedingLinebreak(() => parseExpected(keywords[0].keyword, keywords[0].declare));
        if (keywords.length > 1) {
            for (let i = 1; i < keywords.length; i++) {
                disallowPrecedingLinebreak(() => parseExpected(keywords[i].keyword, keywords[i].declare));
            }
        }
    }

    function parseExpectedToken<T extends SyntaxKind>(flag: T, diagnosticMessage?: DiagnosticMessage, arg0?: any): Token<T> {
        return parseOptionalToken(flag) || createMissingNode(flag, false, diagnosticMessage || errorMessages.unexpectedToken, arg0 || tokenToString(flag));
    }

    function parseExpectedNode<T extends Node>(flag: T['kind'], parseNode: () => T, diagnosticMessage?: DiagnosticMessage, arg0?: any): T;
    function parseExpectedNode<T extends Node>(flag: T['kind'], diagnosticMessage?: DiagnosticMessage, arg0?: any): T;
    function parseExpectedNode<T extends Node>(flag: T['kind'], arg0?: DiagnosticMessage | (() => T), arg1?: DiagnosticMessage | any, arg2?: any): T {
        let diagnosticMessage: DiagnosticMessage = errorMessages.unexpectedToken;
        let arg: any;
        let callback: (() => T) | undefined;
        if (isDiagnosticMessage(arg0)) {
            diagnosticMessage = arg0;
        }
        else if (arg0 !== undefined) {
            callback = arg0;
        }

        if (isDiagnosticMessage(arg1)) {
            diagnosticMessage = arg1;
        }
        else {
            arg = arg1;
        }

        if (arg2 !== undefined) {
            arg = arg2;
        }

        if (currentToken === flag) {
            return callback ? callback() : parseTokenNode<T>();
        }
        return createMissingNode<T>(flag, false, diagnosticMessage, arg || tokenToString(flag));
    }

    function parseExpectedNodeWithLineFeed<T extends Node>(flag: T['kind'], parseNode: () => T, diagnosticMessage?: DiagnosticMessage, arg0?: any): T {
        if (currentToken === flag) {
            const node = parseNode();
            if (!hasPrecedingLinebreak()) {
                raise(errorMessages.requireLineFeed, getStartPos(), getStartPos());
            }
            return node;
        }
        return createMissingNode<T>(flag, false, diagnosticMessage || errorMessages.unexpectedToken, arg0 || tokenToString(flag));
    }

    function parseOption(): OptionStatement {
        const start = getNodeStart();
        parseExpected(SyntaxKind.optionKeyword);
        let keyword: OptionSettingKeyword;
        switch (currentToken) {
            case SyntaxKind.implicitKeyword:
                keyword = parseTokenNode<Token<SyntaxKind.implicitKeyword>>();
                // implicit和explicit互斥
                optionFlag &= (~OptionFlag.explicit);
                optionFlag |= OptionFlag.implicit;
                break;
            case SyntaxKind.explicitKeyword:
                keyword = parseTokenNode<Token<SyntaxKind.explicitKeyword>>();
                // explicit和implicit互斥
                optionFlag &= (~OptionFlag.implicit);
                optionFlag |= OptionFlag.explicit;
                break;
            case SyntaxKind.globalVariablesKeyword:
                keyword = parseTokenNode<Token<SyntaxKind.globalVariablesKeyword>>();
                optionFlag |= OptionFlag.globalVariables;
                break;
            default:
                keyword = createMissingNode<Token<SyntaxKind.explicitKeyword>>(SyntaxKind.explicitKeyword);
                optionFlag = OptionFlag.explicit;
                break;
        }
        return finishNode(factory.createOptionStatement(keyword), start);
    }

    function createMissingNode<T extends Node>(flag: T["kind"], reportAtCurrentLocation?: false, message?: DiagnosticMessage, ...arg0: string[]): T;
    function createMissingNode<T extends Node>(flag: T["kind"], reportAtCurrentLocation: boolean, message: DiagnosticMessage, ...arg0: string[]): T;
    function createMissingNode<T extends Node>(flag: T["kind"], reportAtCurrentLocation?: boolean, message?: DiagnosticMessage, ...arg0: string[]): T {

        if (reportAtCurrentLocation !== undefined && message !== undefined) {
            if (reportAtCurrentLocation) {
                let startPos = getStartPos();
                raise(message, startPos, startPos, ...arg0);
            }
            else {
                raise(message, ...arg0);
            }
        }

        const start = getNodeStart();
        const result =
            flag === SyntaxKind.identifier ? factory.createIdentifier("") :
            flag === SyntaxKind.numberLiteral ? factory.createNumberLiteral("", LiteralType.number) :
            flag === SyntaxKind.stringLiteral ? factory.createStringLiteral("", LiteralType.singleLineString) :
            flag === SyntaxKind.categoricalLiteral ? factory.createCategoricalLiteral() :
            flag === SyntaxKind.categoricalItemLiteral ? factory.createCategoricalItemLiteral() :
            factory.createToken(flag);
        return finishNode(result, start, start) as T;
    }

    function getOriginIdentifier(text: string): string {
        let lowerName = text.toLowerCase();
        let identifier = originIdentifiers.get(lowerName);
        if (identifier === undefined) {
            originIdentifiers.set(lowerName, text);
            identifier = text;
        }
        return identifier;
    }

    function createNodeArray<T extends ReadonlyTextRange>(elements: readonly T[], start: number, end?: number): NodeArray<T> {
        const array = factory.createNodeArray(elements);
        setTextRangeStartEnd(array, start, end ?? getStartPos());
        return array;
    }

    function createMissingExpression(start: number): EmptyExpr {
        const expr = factory.createEmptyExpression();
        setTextRangeStartEnd(expr, start, start);
        return expr;
    }

    /**
     * 将参数宏的参数值视为 NodeArray 进行读取, 一直读取到换行为止, 对于括号和逗号, 需要进行配对检查:
     * + 参数宏实参内有未结束的左括号 '(' 时, 将逗号 ',' 视为实参
     * + 参数宏结尾时, 匹配最后一右括号 ')', 除了留给外部语句的右括号, 都视为实参
     *
     * @returns
     */
    function parseParameterMacroArguments(): ParameterMacroArgument[] {
        const args: ParameterMacroArgument[] = [];
        let innerParen: number = 0;
        let outterParen: number = contextHandler.count(ParserContext.paren);

        parseExpected(SyntaxKind.openParenthesis);
        const nodes: Node[] = [];
        // 需要注意: 读取参数宏调用时, 允许直接换行, 不需要换行符
        const savedContext = scanner.saveState().context;
        scanner.setContext(ScannerContextType.preprocessor);
        while (!hasPrecedingLinebreak()) {
            nodes.push(parseTokenNode());
        }
        scanner.setContext(savedContext);

        return args;
    }

    // Parameter Macro 调用换行不需要换行符
    function parseParameterMacroArgument(): ParameterMacroArgument {
        const start = getNodeStart();
        let items: Node[] = [];
        while (!matchOne([ SyntaxKind.comma, SyntaxKind.closeParenthesis, SyntaxKind.eof ])) {
            items.push(parseTokenNode());
        }
        const result = createNodeArray(items, start) as Mutable<ParameterMacroArgument>;
        result.text = scanner.getTokenText(start, getStartPos());
        return result;
    }

    function parseParameterMacroCallExpression(): ParameterMacroCallExpr {
        const start = getNodeStart();
        const name = parseIdentifierName();
        parseExpected(SyntaxKind.openParenthesis);
        const parametersStart = getNodeStart();
        const savedType = scanner.saveState().context;
        const args: ParameterMacroArgument[] = [];
        scanner.setContext(ScannerContextType.preprocessor);
        contextHandler.once(ParserContext.preprocessor | ParserContext.paren, () => {
            while (true) {
                args.push(parseParameterMacroArgument());
                if (matchOne([ SyntaxKind.closeParenthesis, SyntaxKind.eof ])) {
                    break;
                }
                parseExpected(SyntaxKind.comma);
            }
        });
        const parameters = createNodeArray(args, parametersStart);
        parseExpected(SyntaxKind.closeParenthesis);
        scanner.setContext(savedType);
        const node = factory.createParameterMacroCallExpression(name, parameters);
        return finishNode(node, start);
    }

    function createIdentifier(isIdentifier: boolean, diagnosticMessage?: DiagnosticMessage, ...args: string[]): Identifier {
        if (isIdentifier) {
            identifierCount++;
            const start = getNodeStart();
            const text = getOriginIdentifier(normalizeLineFeedCharacter(getTokenText()));
            next();
            const node = factory.createIdentifier(text);
            identifiers.push(node);
            return finishNode(node, start, getStartPos());
        }

        if (match(SyntaxKind.unknown) && scanner.tryScan(() => scanner.reScanInvalidIdentifier() === SyntaxKind.identifier)) {
            return createIdentifier(true);
        }

        identifierCount++;
        let reportAtCurrentLocation = match(SyntaxKind.eof);
        const node = createMissingNode<Identifier>(SyntaxKind.identifier, reportAtCurrentLocation, diagnosticMessage || errorMessages.invalidToken, ...args);
        next();
        return node;
    }

    function speculationHelper<T>(callback: () => T, lookAhead: boolean): T {
        const savedToken = currentToken;
        const savedParseDiagnosticLength = parsingDiagnostics.length;
        const savedIdentifierCount = identifierCount;
        const savedNodeCount = nodeCount;
        const savedPreprocessorNodeCount = preprocessorNodeCount;

        contextHandler.freeze();

        let outsideLookahead = isLookAhead;
        if (!outsideLookahead) {
            isLookAhead = true;
        }

        let result = lookAhead ? scanner.lookAhead(callback) : scanner.tryScan(callback);
        isLookAhead = outsideLookahead;

        contextHandler.unfreeze();

        if (!result || lookAhead) {
            currentToken = savedToken;
            identifierCount = savedIdentifierCount;
            nodeCount = savedNodeCount;
            preprocessorNodeCount = savedPreprocessorNodeCount;
            parsingDiagnostics.length = savedParseDiagnosticLength;
        }

        return result;
    }

    function lookAhead<T>(callback: () => T): T {
        return speculationHelper(callback, true);
    }

    function tryParse<T>(callback: () => T): T {
        return speculationHelper(callback, false);
    }

    function parseExpected(flag: SyntaxKind, diagnosticMessage?: DiagnosticMessage, shouldWalkAdvance?: boolean): boolean;
    function parseExpected(flag: SyntaxKind, checkKeyword?: boolean, diagnosticMessage?: DiagnosticMessage, shouldWalkAdvance?: boolean): boolean;
    function parseExpected(flag: SyntaxKind, arg0?: DiagnosticMessage | boolean, arg1?: boolean | DiagnosticMessage, arg2?: boolean): boolean {
        let shouldWalkAdvance = true;
        if (arg1 !== undefined && typeof arg1 === 'boolean') {
            shouldWalkAdvance = arg1;
        }
        else if (arg2 !== undefined) {
            shouldWalkAdvance = arg2;
        }

        let diagnosticMessage = errorMessages.unexpectedToken;
        let checkKeyword = false;
        if (arg0 !== undefined) {
            if (typeof arg0 === 'boolean') {
                checkKeyword = arg0;
            }
            else {
                diagnosticMessage = arg0;
            }
        }

        if (match(flag)) {
            if (checkKeyword && fileFlag !== FileKind.declare && scanner.isDelcareReservedWord()) {
                raise(errorMessages.keywordCanOnlyUseInDeclareFile, tokenToString(flag));
            }
            if (shouldWalkAdvance) {
                next();
            }
            return true;
        }

        raise(diagnosticMessage, diagnosticMessage === errorMessages.unexpectedToken ? tokenToString(flag) : getTokenText());

        if (shouldWalkAdvance) {
            next();
        }
        return false;
    }

    function parseExpectedSingleLine(flag: SyntaxKind): boolean {
        return disallowPrecedingLinebreak(() => parseExpected(flag));
    }

    function parseExpressionList<T extends Node>(start: SyntaxKind, end: SyntaxKind | undefined, skip: SyntaxKind | undefined, parse: () => T): T[] {
        const list: T[] = [];
        if (parseExpected(start)) {
            while (true) {
                // 如果end为undefined，扫描到行末尾就结束
                if ((end && match(end)) || match(SyntaxKind.eof) || (!end && hasPrecedingLinebreak())) {
                    break;
                }
                list.push(disallowPrecedingLinebreak(parse));
                if (skip && !(end && match(end)) && !(!end && hasPrecedingLinebreak())) {
                    parseExpectedSingleLine(skip);
                }
            }
            if (end !== undefined) {
                parseExpectedSingleLine(end);
            }
        }
        return list;
    }

    function parseStringLiteral(): StringLiteral {
        const stringFlag = scanner.getTokenFlag();
        const literal = parseTokenNode<StringLiteral>() as Mutable<StringLiteral>;
        if ((stringFlag & TokenFlags.multiLineString) > 0) {
            literal.literalType = LiteralType.multiLineString;
        }
        else {
            literal.literalType = LiteralType.singleLineString;
        }
        return literal;
    }

    function parseNumberLiteral(): NumberLiteral {
        const value = scanner.getTokenValue();

        // literal type
        const tokenFlag = scanner.getTokenFlag();
        let isFloat = (tokenFlag & TokenFlags.float) > 0;
        let literalType = LiteralType.number;
        if ((tokenFlag & TokenFlags.hex) > 0) {
            literalType = LiteralType.hexNumber;
        }
        else if ((tokenFlag & TokenFlags.octal) > 0) {
            literalType = LiteralType.octNumber;
        }

        const literal = parseTokenNode<NumberLiteral>() as Mutable<NumberLiteral>;
        literal.literalType = literalType;
        literal.isFloat = isFloat;

        let nodeValue: number = 0;
        if (!literal.isFloat) {
            let radix = 10;
            if (literal.literalType === LiteralType.octNumber) {
                radix = 8;
            }
            else if (literal.literalType === LiteralType.hexNumber) {
                radix = 16;
            }
            try {
                nodeValue = Number.parseInt(value, radix);
            } catch {}
        }
        else if ((scanner.getTokenFlag() & TokenFlags.float) > 0) {
            try {
                nodeValue = Number.parseFloat(value);
            } catch {}
        }
        literal.value = nodeValue;
        return literal;
    }

    function parseTrueLiteral(): TrueLiteral {
        const start = getNodeStart();
        next();
        return finishNode(factory.createTrueLiteral(), start);
    }

    function parseFalseLiteral(): FalseLiteral {
        const start = getNodeStart();
        next();
        return finishNode(factory.createFalseLiteral(), start);
    }

    function parseNullLiteral(): NullLiteral {
        const start = getNodeStart();
        next();
        return finishNode(factory.createNullLiteral(), start);
    }

    function parseLiteralToken(): Literal {
        switch (currentToken) {
            case SyntaxKind.nullKeyword:
                return parseNullLiteral();
            case SyntaxKind.trueKeyword:
                return parseTrueLiteral();
            case SyntaxKind.falseKeyword:
                return parseFalseLiteral();
            case SyntaxKind.numberLiteral:
                return parseNumberLiteral();
            case SyntaxKind.stringLiteral:
                return parseStringLiteral();
            case SyntaxKind.openCurly:
                return parseCategoricalLiteral();
        }
        return createMissingNode<Literal>(getNodeStart());
    }

    function parseIdentifierOrNumber(diagnosticMessage?: DiagnosticMessage, raiseError: boolean = false, shouldWalkAdvance: boolean = true): Identifier | NumberLiteral | undefined {

        if (match(SyntaxKind.identifier)) {
            return parseIdentifier();
        }

        if (match(SyntaxKind.numberLiteral)) {
            return parseNumberLiteral();
        }

        if (raiseError) {
            raise(diagnosticMessage || errorMessages.unexpectedToken, "标识符或数字");
        }

        if (shouldWalkAdvance) {
            next();
        }

        return undefined;
    }

    function parseCategoricalLiteralItem(): CategoricalItemLiteral {
        const start = getNodeStart();
        const exclude = parseOptionalToken<SyntaxKind.caret>(SyntaxKind.caret);
        let lower: NumberLiteral | Identifier | undefined = undefined;
        if (!match(SyntaxKind.dotDot)) {
            lower = parseIdentifierOrNumber(errorMessages.invalidCategoricalItem);
        }
        let dotDot = parseOptionalToken<SyntaxKind.dotDot>(SyntaxKind.dotDot);
        let upper: NumberLiteral | Identifier | undefined = undefined;
        if (!matchOne([ SyntaxKind.comma, SyntaxKind.closeCurly ])) {
            upper = parseIdentifierOrNumber(errorMessages.invalidCategoricalItem);
        }
        return finishNode(factory.createCategoricalItemLiteral(upper, lower, exclude, dotDot), start);
    }

    function parseCategoricalLiteral(): CategoricalLiteral {
        const start = getNodeStart();
        const items = contextHandler.once(
            ParserContext.categorical,
            () => parseExpressionList(SyntaxKind.openCurly, SyntaxKind.closeCurly, SyntaxKind.comma, parseCategoricalLiteralItem)
        );
        return finishNode(factory.createCategoricalLiteral(items), start);
    }

    function isAllowedIdentifier() {
        let isPreproDefineName = contextHandler.test(ParserContext.preprocessor | ParserContext.name);
        return match(SyntaxKind.identifier)
        || (isPreproDefineName && currentToken >= SyntaxKind.firstKeyword && currentToken <= SyntaxKind.lastKeyword)
        || (currentToken >= SyntaxKind.firstSectionKeyword && currentToken <= SyntaxKind.lastSectionKeyword)
        || (currentToken >= SyntaxKind.firstMDMKeyword && currentToken <= SyntaxKind.lastMDMKeyword)
        || ((fileFlag !== FileKind.declare || isPreproDefineName) && currentToken >= SyntaxKind.firstDeclareKeyword && currentToken <= SyntaxKind.lastDeclareKeyword)
        || ((fileFlag !== FileKind.routing || isPreproDefineName) && currentToken === SyntaxKind.routingKeyword)
        ;
    }

    function parseIdentifier(diagnosticMessage?: DiagnosticMessage, ...args: string[]): Identifier {
        return createIdentifier(isAllowedIdentifier(), diagnosticMessage, ...args);
    }

    function parseIdentifierName(diagnosticMessage?: DiagnosticMessage, ...args: string[]): Identifier {
        return createIdentifier(isIdentifierOrReservedWord(currentToken), diagnosticMessage, ...args);
    }

    function parseArrayTypeSignature(fullName: readonly Identifier[]): ArrayTypeSignature {
        const start = getNodeStart();
        let rank = 0;
        while (parseOptional(SyntaxKind.openBracket)) {
            rank++;
            parseExpected(SyntaxKind.closeBracket);
        }
        return fullName.length > 0 ? finishNode(factory.createArrayTypeSignature(fullName[0], fullName, rank), start) : createMissingNode<ArrayTypeSignature>(SyntaxKind.arrayTypeSignature);
    }

    function parseBindingType(): Binding {
        const start = getNodeStart();
        const as = parseExpectedToken(SyntaxKind.asKeyword);
        let type: Identifier[] | ArrayTypeSignature = parseMaybeFullName();
        if (match(SyntaxKind.openBracket)) {
            type = parseArrayTypeSignature(type);
        }
        if (fileFlag !== FileKind.declare) {
            raise(errorMessages.bindingTypeCanOnlyUseInDeclareFile, start, getTextPos());
        }
        return finishNode(factory.createBindingType(as, type), start);
    }

    function parseLocalVariableDeclaration(): VariableDecl {
        const start = getNodeStart();
        const name = parseIdentifierName();
        let bindingType: Binding | undefined = undefined;
        const declaration = factory.createVariableDeclaration(name);
        if (match(SyntaxKind.asKeyword)) {
            bindingType = disallowPrecedingLinebreakNode(parseBindingType, SyntaxKind.bindingType, "符号名");
            (declaration as Mutable<VariableDecl>).bindingType = bindingType;
            (bindingType as Mutable<Binding>).parent = declaration;
        }
        return finishNode(declaration, start);
    }

    function parseLocalArrayDeclarationDimensions(declaraion: ArrayDecl): ArrayDecl {
        if (match(SyntaxKind.openBracket)) {
            let dimensions: (NumberLiteral | EmptyExpr)[] = [];
            while (true) {
                if (match(SyntaxKind.openBracket)) {
                    next();
                    const start = getNodeStart();
                    // []
                    if (match(SyntaxKind.closeBracket)) {
                        next();
                        dimensions.push(createMissingExpression(start));
                        continue;
                    }
                    else if (match(SyntaxKind.numberLiteral)) {
                        // [number]
                        dimensions.push(disallowPrecedingLinebreak(parseNumberLiteral));
                        parseExpected(SyntaxKind.closeBracket);
                        continue;
                    }
                    else {
                        next();
                        dimensions.push(createMissingExpression(start));
                        raise(errorMessages.invalidArrayDeclarationDimension, start, getTextPos());
                        parseExpected(SyntaxKind.closeBracket);
                        continue;
                    }
                }
                break;
            }
            // 多维数组只有最后一个维度允许动态
            if (dimensions.length > 1) {
                for (let i = 0; i < dimensions.length - 1; i++) {
                    const dim = dimensions[i];
                    if (dim.isMissingNode()) {
                        raise(errorMessages.onlyLastArrayDimensionsCanBeDynamic, dim.start - 1, dim.start);
                    }
                }
            }
            factory.updateArrayDeclaration(declaraion, dimensions);
        }
        return declaraion;
    }

    function parseLocalArrayDeclaration(): ArrayDecl {
        const start = getNodeStart();
        const identifier = parseIdentifierName();
        let arrayDeclaration = parseLocalArrayDeclarationDimensions(factory.createArrayDeclaration(identifier));
        if (match(SyntaxKind.asKeyword)) {
            const bindingType = disallowPrecedingLinebreak(parseBindingType);
            (bindingType as Mutable<Binding>).parent = arrayDeclaration;
            (arrayDeclaration as Mutable<ArrayDecl>).bindingType = bindingType;
        }
        return finishNode(arrayDeclaration, start);
    }

    function parseLocalVariableOrArrayDeclaration(): VariableDecl | ArrayDecl {
        const start = getNodeStart();
        if (lookAhead(nextTokenIsOpenBracket)) {
            return finishNode(parseLocalArrayDeclaration(), start);
        }
        else {
            return finishNode(parseLocalVariableDeclaration(), start);
        }
    }

    function parseLocalDeclarations(): LocalDecls {
        const start = getNodeStart();
        const declarations = parseExpressionList(SyntaxKind.dimKeyword, undefined, SyntaxKind.comma, parseLocalVariableOrArrayDeclaration);
        if (declarations.length === 0) {
            raise(errorMessages.lostLocalDeclaration, start, getTextPos());
        }
        return finishNode(factory.createLocalDeclarations(...declarations), start);
    }

    function parseConstantDeclaration(): ConstantDeclaration {
        const start = getNodeStart();
        const aheadComments = getAheadComments(start);
        parseExpected(SyntaxKind.constKeyword);
        const name = lookAhead(parseIdentifier);
        let initialize = parseExpressionSingleLine(true, false);
        if (!initialize.isAssignmentExpression()) {
            raise(errorMessages.invalidAssignmentExpression, initialize);
            initialize = createMissingNode<AssignmentExpression>(SyntaxKind.binaryExpr);
        }
        else if (!isLiteralToken(initialize.right.kind)) {
            raise(errorMessages.constantInitializationMustBeLiteral, initialize.right);
        }
        const declaration = factory.createConstantDeclaration(name, initialize as AssignmentExpression) as Mutable<ConstantDeclaration>;
        if (aheadComments.length > 0) {
            declaration.aheadComments = aheadComments;
        }
        return finishNode(declaration, start);
    }

    function parseConstantSignature(): ConstSignature {
        const start = getNodeStart();
        const aheadComments = getAheadComments(start);
        parseExpected(SyntaxKind.constKeyword);
        const name = parseIdentifier();
        const bindingType = disallowPrecedingLinebreak(parseBindingType);
        const signature = factory.createConstantSignature(name, bindingType) as Mutable<ConstSignature>;
        if (aheadComments.length > 0) {
            signature.aheadComments = aheadComments;
        }
        (bindingType as Mutable<Binding>).parent = signature;
        return finishNode(signature, start);
    }

    function parseParameterSignature(): ParameterSignature {
        const start = getNodeStart();
        const optional = parseOptionalToken(SyntaxKind.optionalKeyword);
        const paramArray = parseOptionalToken(SyntaxKind.paramArrayKeyword);
        let declaration: VariableDecl | ArrayDecl;
        if (lookAhead(nextTokenIsOpenBracket)) {
            declaration = parseLocalArrayDeclaration();
        }
        else {
            declaration = parseLocalVariableDeclaration();
        }
        let initialize: AssignmentExpression | undefined;
        if (match(SyntaxKind.equal)) {
            initialize = parseBinaryExpression(declaration.name, true) as AssignmentExpression;
        }
        return finishNode(factory.createParameterSignature(declaration, optional, paramArray, initialize), start);
    }

    function parseParameterSignatures(): NodeArray<ParameterSignature> {
        if (!match(SyntaxKind.openParenthesis)) {
            const startPos = getStartPos();
            raise(errorMessages.unexpectedToken, startPos, startPos, "(");
            return createNodeArray([], startPos);
        }
        const start = getNodeStart();
        const parameters = parseExpressionList(SyntaxKind.openParenthesis, SyntaxKind.closeParenthesis, SyntaxKind.comma, parseParameterSignature);
        return createNodeArray(parameters, start);
    }

    function parseFunctionSignature(isMethod: boolean = false): FunctionSignature {
        const start = getNodeStart();
        const aheadComments = getAheadComments(start);
        let hasReturn = parseOptional(SyntaxKind.functionKeyword);
        if (!hasReturn) {
            parseExpected(SyntaxKind.subKeyword);
        }
        const functionName = isMethod ? parseIdentifierName() : parseIdentifier();
        const parameters = parseParameterSignatures();
        let bindingType: Binding | undefined;
        if (match(SyntaxKind.asKeyword)) {
            bindingType = disallowPrecedingLinebreak(parseBindingType);
            if (!hasReturn) {
                raise(errorMessages.subroutineShouldHaveNoReturnValue, functionName);
            }
        }
        const signature = factory.createFunctionSignature(functionName, bindingType, parameters);
        if (bindingType) {
            (bindingType as Mutable<Binding>).parent = signature;
        }
        if (aheadComments.length > 0) {
            (signature as Mutable<Node>).aheadComments = aheadComments;
        }
        if (!isMethod) {
            signatures.push(signature);
        }
        return finishNode(signature, start);
    }

    function parseFunctionDeclaration(): FunctionDeclaration {
        const start = getNodeStart();
        const aheadComments = getAheadComments(start);
        let hasReturn = parseOptional(SyntaxKind.functionKeyword);
        if (!hasReturn) {
            parseExpected(SyntaxKind.subKeyword);
        }
        const functionName = parseIdentifier(errorMessages.invalidIdentifierName, getTokenText());
        const node = factory.createFunctionDeclaration(functionName, hasReturn);
        contextHandler.push(hasReturn ? ParserContext.functionDecl : ParserContext.subDecl, node);
        // 函数参数
        const parameters = parseParameterSignatures();
        factory.updateFunctionDeclaration(node, parameters);
        // 函数体
        const body = parseStatementUntil(() => precidateKeywords([ SyntaxKind.endKeyword ], true, false), undefined, true);
        factory.updateFunctionDeclaration(node, body);
        if (parseExpected(SyntaxKind.endKeyword)) {
            if (hasReturn) {
                disallowPrecedingLinebreak(() => parseExpected(SyntaxKind.functionKeyword));
            }
            else {
                disallowPrecedingLinebreak(() => parseExpected(SyntaxKind.subKeyword));
            }
        }
        contextHandler.remove(ParserContext.functionDecl);
        if (aheadComments.length > 0) {
            (node as Mutable<Node>).aheadComments = aheadComments;
        }
        // section内不允许声明函数
        if (contextHandler.test(ParserContext.section)) {
            raise(errorMessages.functionCannotDeclareInSection, node.name);
        }
        else {
            declarations.push(node);
        }
        return finishNode(node, start);
    }

    function parsePropertySignature(): PropertySignature {
        const start = getNodeStart();
        let modifiers: ModifierToken<DeclareModifierKind>[] = [];
        let aheadComments = getAheadComments(start);

        if (!match(SyntaxKind.propertyKeyword)) {
            while (true) {
                const node = parseTokenNode<Node>();
                if (node.isModifierToken() && !modifiers.find(m => m.kind === node.kind)) {
                    modifiers.push(node);
                }
                else {
                    raise(errorMessages.invalidModifier, node);
                }

                if (matchOne([ SyntaxKind.propertyKeyword, SyntaxKind.eof ]) || hasPrecedingLinebreak()) {
                    break;
                }
            }
        }

        if ((modifiers.length > 0 && hasPrecedingLinebreak()) || match(SyntaxKind.eof)) {
            return createMissingNode<PropertySignature>(SyntaxKind.propertySignature);
        }

        parseExpected(SyntaxKind.propertyKeyword);
        const name = disallowPrecedingLinebreak(parseIdentifierName);
        const parameters = parseParameterSignatures();
        const bindingType = disallowPrecedingLinebreak(parseBindingType);
        const signature = factory.createPropertySignature(name, bindingType, modifiers, parameters as ReadonlyArray<ParameterSignature>);
        (bindingType as Mutable<Binding>).parent = signature;
        (signature as Mutable<PropertySignature>).aheadComments = aheadComments;

        return finishNode(signature, start);
    }

    function parseMaybeFullName(): Identifier[] {
        let fullName: Identifier[] = [];
        while (true) {
            fullName.push(disallowPrecedingLinebreak(parseIdentifier));
            if (!parseOptional(SyntaxKind.dot)) {
                break;
            }
        }
        return fullName;
    }

    function parseInheritsOrImplementsSignatures(): readonly Identifier[][] {
        //parseExpected(SyntaxFlag.inheritsKeyword);
        let implementsInterfaces: Identifier[][] = [];
        while (true) {
            if (hasPrecedingLinebreak() || match(SyntaxKind.implementsKeyword) || match(SyntaxKind.eof)) {
                break;
            }
            implementsInterfaces.push(disallowPrecedingLinebreak(parseMaybeFullName));
            if (!hasPrecedingLinebreak() && !match(SyntaxKind.implementsKeyword) && !match(SyntaxKind.eof)) {
                parseExpected(SyntaxKind.comma);
            }
        }
        return implementsInterfaces;
    }

    function parseClassOrInterfaceSignatureMembers(isClassSignature: boolean): { methods: FunctionSignature[], properties: PropertySignature[], constants: ConstantDeclaration[], defaultMember?: PropertySignature } {
        let methods: FunctionSignature[] = [];
        let properties: PropertySignature[] = [];
        let constants: ConstantDeclaration[] = [];
        let defaultMember: PropertySignature | undefined;

        while (true) {
            if (matchOne([ SyntaxKind.endKeyword, SyntaxKind.eof ])) {
                break;
            }

            switch (currentToken) {
                case SyntaxKind.functionKeyword:
                case SyntaxKind.subKeyword:
                    methods.push(requirePrecedingLinebreak(() => parseFunctionSignature(true)));
                    break;

                case SyntaxKind.readonlyKeyword:
                case SyntaxKind.writeonlyKeyword:
                case SyntaxKind.defaultKeyword:
                case SyntaxKind.propertyKeyword:
                    let property = requirePrecedingLinebreak(parsePropertySignature);
                    properties.push(property);
                    if (property.modifiers && property.modifiers.find(e => e.kind === SyntaxKind.defaultKeyword)) {
                        defaultMember = property;
                    }
                    break;

                case SyntaxKind.constKeyword:
                    if (isClassSignature) {
                        constants.push(requirePrecedingLinebreak(parseConstantDeclaration));
                        break;
                    }

                default:
                    if (!matchOne([ SyntaxKind.endKeyword, SyntaxKind.eof ])) {
                        raise(errorMessages.invalidToken);
                        next();
                    }
                    break;
            }

        }
        return { methods, properties, constants, defaultMember };
    }

    function parseInterfaceSignature(module?: ModuleSignature): InterfaceSignature {
        const start = getNodeStart();
        let aheadComments = getAheadComments(start);
        parseExpected(SyntaxKind.interfaceKeyword, true);
        const name = disallowPrecedingLinebreak(parseIdentifier);
        let inherits: readonly (Identifier[])[] | undefined;
        if (parseOptional(SyntaxKind.inheritsKeyword, false, true)) {
            inherits = disallowPrecedingLinebreak(parseInheritsOrImplementsSignatures);
        }
        else if (!hasPrecedingLinebreak()) {
            raise(errorMessages.unexpectedToken, "Inherits");
        }

        const node = factory.createInterfaceSignature(name, inherits) as Mutable<InterfaceSignature>;

        contextHandler.push(ParserContext.interfaceSignature, node);
        const members = requirePrecedingLinebreak(() => parseClassOrInterfaceSignatureMembers(false));
        factory.updateInterfaceSignature(node, inherits, members.properties, members.methods);
        node.default = members.defaultMember;
        contextHandler.remove(ParserContext.interfaceSignature);

        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.interfaceKeyword, declare: true } ]);

        (node as Mutable<InterfaceSignature>).aheadComments = aheadComments;
        if (module) {
            (node as Mutable<InterfaceSignature>).module = module;
        }
        else {
            signatures.push(node);
        }

        return finishNode(node, start);
    }

    function parseClassSignature(module?: ModuleSignature): ClassSignature {
        const start = getNodeStart();
        let aheadComments = getAheadComments(start);
        parseExpected(SyntaxKind.classKeyword, true);
        const name = disallowPrecedingLinebreak(parseIdentifier);
        const node = factory.createClassSignature(name);

        // context
        contextHandler.push(ParserContext.classSignature, node);

        let implementsInterface: readonly Identifier[][] | undefined;
        let inherits: readonly Identifier[][] | undefined;
        if (parseOptional(SyntaxKind.inheritsKeyword, false, true)) {
            inherits = disallowPrecedingLinebreak(parseInheritsOrImplementsSignatures);
        }
        if (parseOptional(SyntaxKind.implementsKeyword, false, true)) {
            implementsInterface = disallowPrecedingLinebreak(parseInheritsOrImplementsSignatures);
        }
        const members = parseClassOrInterfaceSignatureMembers(true);

        factory.updateClassSignature(node, implementsInterface, inherits, members.properties, members.methods, members.constants);
        (node as Mutable<ClassSignature>).default = members.defaultMember;

        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.classKeyword, declare: true } ]);

        (node as Mutable<ClassSignature>).aheadComments = aheadComments;

        if (module) {
            (node as Mutable<ClassSignature>).module = module;
        }
        else {
            signatures.push(node);
        }

        return finishNode(node, start);
    }

    function parseEnumMemberSignature(value: number): EnumMemberSignature {
        const start = getNodeStart();
        const aheadComments = getAheadComments(start);
        const name = parseIdentifier();
        let literal: NumberLiteral | undefined;
        if (parseOptional(SyntaxKind.equal, false, true)) {
            literal = parseNumberLiteral();
            value = literal.value;
        }
        const signature = factory.createEnumMemberSignature(name, value, literal);
        (signature as Mutable<EnumMemberSignature>).aheadComments = aheadComments;
        return finishNode(signature, start);
    }

    function parseEnumSignature(module?: ModuleSignature): EnumSignature {
        const start = getNodeStart();
        const aheadComments = getAheadComments(start);
        let count = 0;
        parseExpected(SyntaxKind.enumKeyword, true);
        const name = disallowPrecedingLinebreak(parseIdentifierName);
        const members: EnumMemberSignature[] = [];
        while (true) {
            if (matchOne([ SyntaxKind.endKeyword, SyntaxKind.eof ])) {
                break;
            }
            members.push(requirePrecedingLinebreak(() => parseEnumMemberSignature(count++)));
        }
        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.enumKeyword, declare: true } ]);

        const node = factory.createEnumSignature(name, members);
        (node as Mutable<EnumSignature>).aheadComments = aheadComments;

        if (module) {
            (node as Mutable<EnumSignature>).module = module;
        }
        else {
            signatures.push(node);
        }

        return finishNode(node, start);
    }

    function parseModuleSignature(): ModuleSignature {
        const start = getNodeStart();
        parseExpected(SyntaxKind.moduleKeyword, true);
        let fullName: Identifier[] = [];
        while (lookAhead(nextTokenIsDot)) {
            fullName.push(disallowPrecedingLinebreak(parseIdentifier));
            disallowPrecedingLinebreak(() => parseExpected(SyntaxKind.dot));
        }
        const name = disallowPrecedingLinebreak(() => parseExpectedNodeWithLineFeed(SyntaxKind.identifier, parseIdentifier));
        fullName.push(name);

        const node = factory.createModuleSignature(name, fullName) as Mutable<ModuleSignature>;
        // context
        contextHandler.push(ParserContext.moduleSignature, node);

        const enums: EnumSignature[] = [];
        const interfaces: InterfaceSignature[] = [];
        const classes: ClassSignature[] = [];
        const functions: FunctionSignature[] = [];
        const constants: ConstSignature[] = [];

        let member;

        while (true) {
            if (matchOne([ SyntaxKind.endKeyword, SyntaxKind.eof ])) {
                break;
            }

            switch (currentToken) {
                case SyntaxKind.classKeyword:
                    classes.push(requirePrecedingLinebreak(() => parseClassSignature(node)));
                    break;
                case SyntaxKind.interfaceKeyword:
                    interfaces.push(requirePrecedingLinebreak(() => parseInterfaceSignature(node)));
                    break;
                case SyntaxKind.enumKeyword:
                    enums.push(requirePrecedingLinebreak(() => parseEnumSignature(node)));
                    break;
                case SyntaxKind.constKeyword:
                    member = requirePrecedingLinebreak(parseConstantSignature);
                    (member as Mutable<ConstSignature>).module = node;
                    constants.push(member);
                    break;
                case SyntaxKind.subKeyword:
                case SyntaxKind.functionKeyword:
                    member = requirePrecedingLinebreak(parseFunctionSignature);
                    (member as Mutable<FunctionSignature>).module = node;
                    functions.push(member);
                    break;

                default:
                    raise(errorMessages.unexpectedToken);
                    next();
                    break;
            }
        }

        factory.updateModuleSignature(node, functions, classes, interfaces, enums, constants);
        contextHandler.remove(ParserContext.moduleSignature);

        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.moduleKeyword, declare: true } ]);

        signatures.push(node);
        return finishNode(node, start);
    }

    function parseMemberExpression(object: MemberExpressionObject): MemberExpr {
        const start = object.start;
        parseExpected(SyntaxKind.dot);
        let member: Identifier;
        if (hasPrecedingLinebreak()) {
            member = createMissingNode(SyntaxKind.identifier, true, errorMessages.lostMemberExpressionProperty);
        }
        else {
            member = parseIdentifierName(errorMessages.invalidMemberExpressionProperty);
        }
        return finishNode(factory.createMemberExpression(object, member), start);
    }

    function parseIdentifierOrHeigher(withStatementObject?: Expression, maybeAssignment?: boolean): Literal | Identifier | MemberExpr | CallExpr | IndexExpr | UnaryExpr | BinaryExpression | Expression {
        let node: Literal | Identifier | MemberExpr | CallExpr | IndexExpr;
        const start = getNodeStart();
        // 括号
        if (match(SyntaxKind.openParenthesis)) {
            parseExpected(SyntaxKind.openParenthesis);
            let result = parseUnaryExpressionOrHeigher(withStatementObject, maybeAssignment);
            parseExpectedSingleLine(SyntaxKind.closeParenthesis);
            return result;
        }

        if (isLiteralToken(currentToken) || match(SyntaxKind.openCurly)) {
            return parseLiteralToken();
        }

        if (match(SyntaxKind.notKeyword) || match(SyntaxKind.minus)) {
            return parseUnaryExpressionOrHeigher(withStatementObject, maybeAssignment);
        }

        // 在with语句块内，可能以点'.'开始，成员表达式的Object为With语句的Object
        if (match(SyntaxKind.dot)) {
            node = parseMemberExpression(withStatementObject?.isMemberExpressionObject() ? withStatementObject : createMissingNode<Identifier>(SyntaxKind.identifier, true, errorMessages.lostMemberExpressionObject));
        }
        else {
            node = parseIdentifier();
        }

        while (true) {
            // 如果换行，结束当前表达式
            if (hasPrecedingLinebreak() || match(SyntaxKind.eof)) {
                break;
            }
            // object.member
            if (match(SyntaxKind.dot, false)) {
                finishNode(node, start);
                node = parseMemberExpression(node);
            }
            // object()
            else if (match(SyntaxKind.openParenthesis)) {
                // object不允许是`IndexExpression`或`CallExpression`，如果是的话，直接返回当前的结果
                if (node.isExpression<IndexExpr>(SyntaxKind.indexExpr) || node.isExpression<CallExpr>(SyntaxKind.callExpr)) {
                    return node;
                }
                finishNode(node, start);
                node = contextHandler.once(ParserContext.paren, () => parseCallExpression(node as Callee));
            }
            // object[index]
            else if (match(SyntaxKind.openBracket) && !node.isExpression<CallExpr>(SyntaxKind.callExpr)) {
                finishNode(node, start);
                node = parseIndexExpression(node);
            }
            //
            else {
                break;
            }

        }
        return finishNode(node, start);
    }

    function parseBoundary(): NumberLiteral | Expression {
        const start = getNodeStart();
        if (match(SyntaxKind.numberLiteral)) {
            return finishNode(parseNumberLiteral(), start);
        }
        return finishNode(parseExpressionSingleLine(false, true), start);
    }

    // object[.. <options>].method
    // object[.. <options>].property = expression
    // <options> ::= [In categories]
    function parseObjectCollectionIterator(): ObjectCollectionIterator {
        const start = getNodeStart();
        const dotDot = parseTokenNode<Token<SyntaxKind.dotDot>>();
        let categories: Identifier | undefined;
        if (match(SyntaxKind.inKeyword)) {
            categories = nextAnd(() => parseIdentifier(errorMessages.invalidObjectCollectionIteratorCategoies));
        }
        return finishNode(factory.createObjectCollectionIterator(dotDot, categories), start);
    }

    function parseIndexExpressionIndex(): IndexExprIndex {
        // object[]
        if (match(SyntaxKind.closeBracket)) {
            raise(errorMessages.unexpectedToken, "表达式");
            return createMissingExpression(scanner.getTextPos());
        }
        // object[.. [In categoires]]
        if (match(SyntaxKind.dotDot)) {
            return disallowPrecedingLinebreak(parseObjectCollectionIterator);
        }
        let nextIsCloseBracket = lookAhead(() => nextIs(SyntaxKind.closeBracket));
        // object[literal]
        if (match(SyntaxKind.stringLiteral) && nextIsCloseBracket) {
            return disallowPrecedingLinebreak(parseStringLiteral);
        }
        if (match(SyntaxKind.numberLiteral) && nextIsCloseBracket) {
            return disallowPrecedingLinebreak(parseNumberLiteral);
        }
        // object[identifier]
        if (match(SyntaxKind.identifier) && nextIsCloseBracket) {
            return disallowPrecedingLinebreak(parseIdentifier);
        }
        // object[expression]
        return parseExpressionSingleLine(false, true);
    }

    // object[.. [In categories]]
    // object[number]
    // object[string]
    // object[identifier]
    // object[expression]
    function parseIndexExpression(object: IndexExprObject): IndexExpr {
        const start = object.start;
        // skip '['
        parseExpected(SyntaxKind.openBracket);
        const index = parseIndexExpressionIndex();
        parseExpected(SyntaxKind.closeBracket);
        return finishNode(factory.createIndexExpression(object, index), start);
    }

    function parseCallExpressionArguments(): Argument[] {
        let args: Argument[] = parseExpressionList(SyntaxKind.openParenthesis, SyntaxKind.closeParenthesis, SyntaxKind.comma, () => {
            let result;
            if (match(SyntaxKind.comma)) {
                result = createMissingExpression(getNodeStart());
            }
            else {
                result = parseExpressionSingleLine(false, true);
            }
            return result;
        });
        return args;
    }

    function parseCallExpression(callee: Callee): CallExpr {
        const node = factory.createCallExpression(callee, []) as Mutable<CallExpr>;
        contextHandler.push(ParserContext.parameters, node);
        const args = disallowPrecedingLinebreak(parseCallExpressionArguments);
        contextHandler.remove(ParserContext.parameters);
        factory.updateCallExpression(node, callee, args);
        return finishNode(node, callee.start);
    }

    function parseUnaryExpression(): UnaryExpr {
        const start = getNodeStart();
        let operator: Token<UnaryOperatorKind> = parseTokenNode();
        if (operator.kind === SyntaxKind.exclamation && !isPreprocessorContext()) {
            raise(errorMessages.tokenCanOnlyUseInPPContext, operator, operator.text);
        }
        return finishNode(factory.createUnaryExpression(operator, parseExpressionSingleLine(false, true)), start);
    }

    function convertUnaryExpressionToNumberLiteral(expression: UnaryExpr): NumberLiteral {
        const expr = expression.expression;
        if (expr.isNumberLiteral() && expression.operator.kind === SyntaxKind.minus) {
            const text = "-" + expr.text;
            const value = expr.value * (-1);
            const node = factory.createNumberLiteral(value, LiteralType.number) as Mutable<NumberLiteral>;
            node.text = text;
            return finishNode(node, expression.start, expression.end);
        }
        return createMissingNode<NumberLiteral>(SyntaxKind.numberLiteral);
    }

    function parseBinaryExpression(left: Expression, maybeAssignment: boolean = false) {
        const start = left.start;
        const operator = parseTokenNode<Token<BinaryOperatorKind>>();
        if (isPreprocessorOperatorToken(operator.kind) && !isPreprocessorContext()) {
            raise(errorMessages.tokenCanOnlyUseInPPContext, operator, operator.text);
            factory.updateNode(operator, convertPreprocessorOperatorToEquivalentToken(operator.kind));
        }
        const right = parseExpressionSingleLine(false, true);
        let node;
        if (maybeAssignment && operator.isToken(SyntaxKind.equal)) {
            node = factory.createAssignmentExpression(operator, left, right);
        }
        else {
            // 检查左值是否是二元表达式，如果是，需要检查左侧操作符和当前操作符的优先性，
            // 如果优先性低于当前操作符，需要将左侧表达式的右值和当前表达式的右值合并成新的右值：
            // left:                                | right:
            //  left.left left.operator left.right  | (left or left.right) right.operator right.right
            // 如果 right.operator的优先性 > left.operator的优先性 =>
            //   left.left left.operator (left.right right.operator right.right)
            // 否则
            //   left.left left.operator left.right right.operator right.right
            if (left.isExpression<BinaryExpression>(SyntaxKind.binaryExpr)) {
                let leftPrecedence = getOperatorPrecedence(left.operator.kind);
                let currentPrecedence = getOperatorPrecedence(operator.kind);
                if (leftPrecedence >= currentPrecedence) {
                    node = factory.createBinaryExpression(operator, left, right);
                }
                else {
                    let updatedRight = factory.createBinaryExpression(operator, left.right, right);
                    node = factory.updateBinaryExpression(left, left.left, updatedRight);
                }
            }
            else {
                node = factory.createBinaryExpression(operator, left, right);
            }
        }
        return finishNode(node, start);
    }

    // Set objectvar = objectexpression
    function parseSetAssignmentExpression(): AssignmentExpression {
        const start = getNodeStart();
        const set = requirePrecedingLinebreak(() => parseExpectedNode<Token<SyntaxKind.setKeyword>>(SyntaxKind.setKeyword));
        const expression = parseExpressionSingleLine(true, false);
        if (!expression.isAssignmentExpression()) {
            return createMissingNode<AssignmentExpression>(SyntaxKind.binaryExpr, false, errorMessages.invalidAssignmentExpression);
        }
        (expression as Mutable<AssignmentExpression>).set = set;
        return finishNode(expression, start);
    }

    //  lower-boundary [to] upper-boundary
    function parseIterationExpression(): IterationExpr {
        const start = getNodeStart();
        const lowerBoundary = parseBoundary();
        parseExpected(SyntaxKind.toKeyword);
        const upperBoundary = parseBoundary();
        return finishNode(factory.createIterationExpression(lowerBoundary, upperBoundary), start);
    }

    function parseBinaryExpressionOrHeigher(withStatementObject?: Expression, maybeAssignment?: boolean): Expression {
        if (match(SyntaxKind.setKeyword)) {
            return parseSetAssignmentExpression();
        }
        let leftOperand = parseIdentifierOrHeigher(withStatementObject, maybeAssignment);
        if (isBinaryOperatorToken(currentToken)) {
            return disallowPrecedingLinebreak(() => parseBinaryExpression(leftOperand, maybeAssignment));
        }
        return leftOperand;
    }

    function parseUnaryExpressionOrHeigher(withStatementObject?: Expression, maybeAssignment?: boolean): Expression {
        if (match(SyntaxKind.notKeyword) || match(SyntaxKind.minus)) {
            let unaryExpr = parseUnaryExpression();
            if (unaryExpr.operator.kind === SyntaxKind.minus && unaryExpr.expression.isNumberLiteral()) {
                return convertUnaryExpressionToNumberLiteral(unaryExpr);
            }
            return unaryExpr;
        }
        return parseBinaryExpressionOrHeigher(withStatementObject, maybeAssignment);
    }

    function parseExpressionSingleLine(allowAssignment: boolean, allowParen: boolean): Expression {
        return disallowPrecedingLinebreak(() => parseExpression(allowAssignment, allowParen));
    }

    function parseExpression(allowAssignment: boolean, allowParen: boolean): Expression {
        const start = getNodeStart();
        let expression: Expression;
        let withStatementObject: Expression | undefined;
        if (contextHandler.test(ParserContext.withStat)) {
            let currentWith = currentWithStatement();
            withStatementObject = currentWith ? currentWith.object : undefined;
        }
        // 左侧括号
        if (parseOptional(SyntaxKind.openParenthesis, false, true)) {
            return contextHandler.once(ParserContext.paren, () => {
                if (!allowParen) {
                    raise(errorMessages.syntaxError, getTokenText());
                }
                expression = parseExpression(allowAssignment, allowParen);
                if (!parseExpected(SyntaxKind.closeParenthesis)) {
                    raise(errorMessages.unexpectedToken, ")");
                }
                if (isBinaryOperatorToken(currentToken)) {
                    expression = parseBinaryExpression(expression, allowAssignment);
                }
                return expression;
            });
        }

        expression = parseUnaryExpressionOrHeigher(withStatementObject, allowAssignment);
        return finishNode(expression, start);
    }

    function hasPrecedingLinebreak(): boolean {
        return scanner.hasPrecedingLinebreak();
    }

    function parseExpressionStatement(): ExprStat {
        const start = getNodeStart();
        const expression = parseExpression(true, true);
        return finishNode(factory.createExpressionStatement(expression), start);
    }

    function parseSingleLineExpressionLikeStatement(): ExprStat | JumpStatement {
        if (matchOne([ SyntaxKind.gotoKeyword, SyntaxKind.exitKeyword, SyntaxKind.onKeyword, SyntaxKind.resumeKeyword ])) {
            return parseJumpStatement();
        }
        return parseExpressionStatement();
    }

    function parseStatement(): Statement {
        switch (currentToken) {
            case SyntaxKind.dimKeyword:
                return requirePrecedingLinebreak(parseLocalDeclarations);

            case SyntaxKind.identifier:
                if (lookAhead(() => nextIs(SyntaxKind.colon))) {
                    const start = getNodeStart();
                    const name = requirePrecedingLinebreak(parseIdentifier);
                    next();
                    return finishNode(factory.createLocation(name), start);
                }
                break;

            case SyntaxKind.ifKeyword:
                return requirePrecedingLinebreak(parseIfStatement);
            case SyntaxKind.forKeyword:
                return requirePrecedingLinebreak(parseForLikeStatement);
            case SyntaxKind.doKeyword:
                return requirePrecedingLinebreak(parseDoStatement);
            case SyntaxKind.whileKeyword:
                return requirePrecedingLinebreak(parseWhileStatement);
            case SyntaxKind.selectKeyword:
                return requirePrecedingLinebreak(parseSelectStatement);
            case SyntaxKind.withKeyword:
                return requirePrecedingLinebreak(parseWithStatement);
            case SyntaxKind.sectionKeyword:
                return requirePrecedingLinebreak(parseSectionStatement);

            case SyntaxKind.optionKeyword:
                return requirePrecedingLinebreak(parseOption);

            case SyntaxKind.gotoKeyword:
            case SyntaxKind.onKeyword:
            case SyntaxKind.exitKeyword:
                return requirePrecedingLinebreak(parseJumpStatement);

            case SyntaxKind.resumeKeyword:
                return requirePrecedingLinebreak(parseResumeStatement);

            case SyntaxKind.constKeyword:
                if (fileFlag === FileKind.declare) {
                    const node = requirePrecedingLinebreak(parseConstantSignature);
                    signatures.push(node);
                    return node;
                }
                return requirePrecedingLinebreak(parseConstantDeclaration);

            case SyntaxKind.functionKeyword:
            case SyntaxKind.subKeyword:
                if (fileFlag === FileKind.declare) {
                    return requirePrecedingLinebreak(parseFunctionSignature);
                }
                return requirePrecedingLinebreak(parseFunctionDeclaration);

            // declare
            case SyntaxKind.moduleKeyword:
            case SyntaxKind.classKeyword:
            case SyntaxKind.interfaceKeyword:
            case SyntaxKind.enumKeyword:
                if (fileFlag !== FileKind.declare) {
                    break;
                }
                return currentToken === SyntaxKind.moduleKeyword ? requirePrecedingLinebreak(parseModuleSignature) :
                    currentToken === SyntaxKind.classKeyword ? requirePrecedingLinebreak(parseClassSignature) :
                    currentToken === SyntaxKind.interfaceKeyword ? requirePrecedingLinebreak(parseInterfaceSignature) :
                    requirePrecedingLinebreak(parseEnumSignature);

            // section
            case SyntaxKind.jobKeyword:
            case SyntaxKind.inputDataSourceKeyword:
            case SyntaxKind.outputDataSourceKeyword:
            case SyntaxKind.globalSQLVariablesKeyword:
            case SyntaxKind.metadataKeyword:
            case SyntaxKind.loggingKeyword:
            case SyntaxKind.eventKeyword:
                // 如果当前文件不是DMS文件或者已经在Event Section内部或者下一个Token不是'('，视为表达式
                if (contextHandler.test(ParserContext.eventSection) || fileFlag !== FileKind.dms || !lookAhead(nextTokenIsOpenParenthesis)) {
                    break;
                }
                return currentToken === SyntaxKind.jobKeyword ? requirePrecedingLinebreak(parseJobSection) :
                    currentToken === SyntaxKind.inputDataSourceKeyword ? requirePrecedingLinebreak(parseInputDataSourceSection) :
                    currentToken === SyntaxKind.outputDataSourceKeyword ? requirePrecedingLinebreak(parseOutputDataSourceSection) :
                    currentToken === SyntaxKind.globalSQLVariablesKeyword ? requirePrecedingLinebreak(parseGlobalSQLVariablesSection) :
                    currentToken === SyntaxKind.metadataKeyword ? requirePrecedingLinebreak(parseMetadataSection) :
                    currentToken === SyntaxKind.loggingKeyword ? requirePrecedingLinebreak(parseLoggingSection) :
                    requirePrecedingLinebreak(parseEventSection);

            case SyntaxKind.routingKeyword:
                if (contextHandler.test(ParserContext.routingSection | ParserContext.eventSection) || fileFlag !== FileKind.routing || !lookAhead(nextTokenIsOpenParenthesis)) {
                    break;
                }
                return requirePrecedingLinebreak(parseRoutingSection);

            // preprocessor

            case SyntaxKind.ppDefineKeyword:
                return requirePrecedingLinebreak(parsePreprocessorDefineStatement);
            case SyntaxKind.ppUndefKeyword:
                return requirePrecedingLinebreak(parsePreprocessorUndefStatement);
            case SyntaxKind.ppIncludeKeyword:
                return requirePrecedingLinebreak(parsePreprocessorIncludeStatement);
            case SyntaxKind.ppIfKeyword:
                return requirePrecedingLinebreak(parsePreprocessorIfStatement);
            case SyntaxKind.ppIfDefKeyword:
                return requirePrecedingLinebreak(parsePreprocessorIfDefStatement);
            case SyntaxKind.ppIfNDefKeyword:
                return requirePrecedingLinebreak(parsePreprocessorIfNDefStatement);
            case SyntaxKind.ppErrorKeyword:
                return requirePrecedingLinebreak(parsePreprocessorErrorStatement);
            case SyntaxKind.ppLineKeyword:
                return requirePrecedingLinebreak(parsePreprocessorLineStatement);

        }

        return requirePrecedingLinebreak(() => parseExpressionStatement());
    }

    function parseStatementUntil(precidate: () => boolean, statementCallback?: (stat: Statement) => void, locallineLocationScope: boolean = false): Block {
        let statements: Statement[] = [];
        const start = getNodeStart();

        let localLocations: LineLocation[] = [];
        if (!locallineLocationScope) {
            localLocations = locations;
        }
        while (!precidate()) {
            let element = parseStatement();
            statementCallback?.(element);
            statements.push(element);
            if (element.isStatement<LineLocation>(SyntaxKind.location)) {
                localLocations.push(element);
            }
        }

        let block = factory.createBlockStatement(statements) as Mutable<Block>;
        block.locations.nodes.push(...localLocations);
        return finishNode(block, start, statements.length === 0 ? start : undefined);
    }

    function precidateKeywords(flags: SyntaxKind[], requriePrecedingLineFeed: boolean = true, requireFollowLineFeed: boolean = true, eofMessage?: string, keywordCallback?: (keyword: Node) => void): boolean {

        flags.push(SyntaxKind.eof);

        if (matchOne(flags)) {

            let hasLineFeed = hasPrecedingLinebreak();
            let lineFeedFollowKeyword = false;
            let tokenStartNextKeyword = getTextPos();
            let keyword = lookAhead(() => {
                let k = parseExpectedNode(currentToken);
                lineFeedFollowKeyword = hasPrecedingLinebreak();
                tokenStartNextKeyword = getNodeStart();
                return k;
            });

            if (keywordCallback) {
                keywordCallback(keyword);
            }

            if (eofMessage && match(SyntaxKind.eof)) {
                raise(errorMessages.lostKeyword, eofMessage);
            }

            if (requriePrecedingLineFeed && !hasLineFeed) {
                raise(errorMessages.requireLineFeed, keyword);
            }

            if (requireFollowLineFeed && !lineFeedFollowKeyword) {
                raise(errorMessages.requireLineFeed, tokenStartNextKeyword, tokenStartNextKeyword + 1);
            }

            return true;
        }

        return false;
    }

    function parseJumpLocation(): Identifier | NumberLiteral {
        if (match(SyntaxKind.numberLiteral)) {
            const literal = parseNumberLiteral();
            if (literal.value !== 0) {
                raise(errorMessages.invalidLocation);
            }
            return literal;
        }
        return parseIdentifier();
    }

    function parseExitPrecedure(): KeywordToken<PrecedureCanExit> {
        const start = getNodeStart();

        if (match(SyntaxKind.subKeyword)) {
            if (!contextHandler.test(ParserContext.subDecl)) {
                raise(errorMessages.wrongExitPrecedure, "Sub");
            }
            return parseTokenNode<KeywordToken<SyntaxKind.subKeyword>>();
        }

        if (match(SyntaxKind.functionKeyword)) {
            if (!contextHandler.test(ParserContext.functionDecl)) {
                raise(errorMessages.wrongExitPrecedure, "Function");
            }
            return parseTokenNode<KeywordToken<SyntaxKind.functionKeyword>>();
        }

        if (match(SyntaxKind.forKeyword)) {
            if (!contextHandler.test(ParserContext.forStat)) {
                raise(errorMessages.wrongExitPrecedure, "For");
            }
            return parseTokenNode<KeywordToken<SyntaxKind.forKeyword>>();
        }

        if (match(SyntaxKind.doKeyword)) {
            if (!contextHandler.test(ParserContext.doStat)) {
                raise(errorMessages.wrongExitPrecedure, "Do");
            }
            return parseTokenNode<KeywordToken<SyntaxKind.doKeyword>>();
        }

        if (match(SyntaxKind.whileKeyword)) {
            if (!contextHandler.test(ParserContext.whileStat)) {
                raise(errorMessages.wrongExitPrecedure, "While");
            }
            return parseTokenNode<KeywordToken<SyntaxKind.whileKeyword>>();
        }

        raise(errorMessages.invalidExitPrecedure, tokenToString(currentToken));
        return createMissingNode<KeywordToken<PrecedureCanExit>>(start);
    }

    // Resume Next
    function parseResumeStatement(): ResumeStatement {
        const start = getNodeStart();
        const resume = parseExpectedNode<KeywordToken<SyntaxKind.resumeKeyword>>(SyntaxKind.resumeKeyword);
        const next = parseExpectedNode<KeywordToken<SyntaxKind.nextKeyword>>(SyntaxKind.nextKeyword);
        return finishNode(factory.createResumeStatement(resume, next), start);
    }

    // Goto location
    // On Error Goto location
    // On Error Resume Next
    // On Error Goto 0
    // Exit
    function parseJumpStatement(): JumpStatement {
        const start = getNodeStart();

        let exit: KeywordToken<SyntaxKind.exitKeyword> | undefined;
        let exitPrecedure: KeywordToken<PrecedureCanExit> | undefined;
        let goto: KeywordToken<SyntaxKind.gotoKeyword> | undefined;
        let location: Identifier | NumberLiteral | undefined;
        let resume: ResumeStatement | undefined;
        let on: KeywordToken<SyntaxKind.onKeyword> | undefined;
        let error: KeywordToken<SyntaxKind.errorKeyword> | undefined;

        if (match(SyntaxKind.onKeyword)) {
            on = parseTokenNode<KeywordToken<SyntaxKind.onKeyword>>();
            error = parseExpectedNode<KeywordToken<SyntaxKind.errorKeyword>>(SyntaxKind.errorKeyword);
            if (match(SyntaxKind.gotoKeyword)) {
                goto = parseExpectedNode<KeywordToken<SyntaxKind.gotoKeyword>>(SyntaxKind.gotoKeyword);
                location = disallowPrecedingLinebreak(parseJumpLocation);
                const onErrorGotoStatement = factory.createJumpStatement(goto, location) as Mutable<JumpStatement>;
                onErrorGotoStatement.on = on;
                onErrorGotoStatement.error = error;
                onErrorGotoStatement.asChildren(on, error);
                return finishNode(onErrorGotoStatement, start);
            } else {
                resume = parseResumeStatement();
                const onErrorResume = factory.createJumpStatement(resume) as Mutable<JumpStatement>;
                onErrorResume.on = on;
                onErrorResume.error = error;
                onErrorResume.asChildren(on, error);
                return finishNode(onErrorResume, start);
            }
        }
        else if (match(SyntaxKind.gotoKeyword)) {
            goto = parseExpectedNode<KeywordToken<SyntaxKind.gotoKeyword>>(SyntaxKind.gotoKeyword);
            location = disallowPrecedingLinebreak(parseJumpLocation);
            return finishNode(factory.createJumpStatement(goto, location), start);
        }
        else if (match(SyntaxKind.exitKeyword)) {
            exit = parseTokenNode<KeywordToken<SyntaxKind.exitKeyword>>();
            if (!hasPrecedingLinebreak()) {
                exitPrecedure = parseExitPrecedure();
            }
            return finishNode(factory.createJumpStatement(exit, exitPrecedure), start);
        }

        return finishNode(createMissingNode<JumpStatement>(SyntaxKind.jumpStat), start);
    }

    function parseIfStatement(): IfStat {
        const start = getNodeStart();
        // 以`if`关键字开始的语句，才检查末尾可能的'end if'
        let ifStart = false;
        if (match(SyntaxKind.ifKeyword)) {
            parseExpected(SyntaxKind.ifKeyword);
            ifStart = true;
        }
        else {
            parseExpected(SyntaxKind.elseifKeyword);
        }

        const condition = parseExpressionSingleLine(false, true);
        parseExpectedSingleLine(SyntaxKind.thenKeyword);
        let singleLine = !hasPrecedingLinebreak();

        const node = factory.createIfStatement(condition, factory.createStatement(SyntaxKind.exprStat)) as Mutable<IfStat>;

        contextHandler.push(ParserContext.ifStat, node);
        // then 后可能是多行 :
        // 1. 如果是多行，遇到'Else'/'ElseIf'/'End'中的任意一个将结束语句块
        // 2. 如果是单行，遇到'Else'或`hasPrecedingLineBreak() = true`时结束语句块
        const thenStatement = singleLine ? parseSingleLineExpressionLikeStatement() : parseStatementUntil(() => precidateKeywords([ SyntaxKind.elseifKeyword, SyntaxKind.elseKeyword, SyntaxKind.endKeyword ], !singleLine, false, "End If"));

        // then expression后，可能出现：
        // 1. 多行时，遇到`Else`/`ElseIf`时，将进入`node.else`语句块
        // 2. 单行时，遇到`Else`时，进入`node.else`语句块，但是需要明确当前`IfStatement`是单行语句
        let elseStatement: Statement | undefined = undefined;
        // ElseIf
        if (match(SyntaxKind.elseifKeyword) && !singleLine) {
            elseStatement = requirePrecedingLinebreak(parseIfStatement);
        }
        // Else
        else if (match(SyntaxKind.elseKeyword) && ((singleLine && !hasPrecedingLinebreak()) || (!singleLine && hasPrecedingLinebreak()))) {
            node.elseKeyword = parseTokenNode<Token<SyntaxKind.elseKeyword>>();
            if (singleLine) {
                elseStatement = parseExpressionStatement();
            } else {
                elseStatement = parseStatementUntil(() => precidateKeywords([ SyntaxKind.endKeyword ], false, false, "End If"));
            }
        }

        factory.updateIfStatement(node, thenStatement, elseStatement);
        factory.updateIfStatement(node, singleLine);

        if (!singleLine && ifStart) {
            parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.ifKeyword, declare: false } ]);
        }
        contextHandler.remove(ParserContext.ifStat);

        return finishNode(node, start);
    }

    function parseForStatement(): ForStat {
        const start = getNodeStart();
        parseExpected(SyntaxKind.forKeyword);
        const counter = disallowPrecedingLinebreak(parseIdentifier);
        parseExpectedSingleLine(SyntaxKind.equal);
        const range = disallowPrecedingLinebreak(parseIterationExpression);
        let step: NumberLiteral | undefined = undefined;
        if (match(SyntaxKind.stepKeyword)) {
            step = disallowPrecedingLinebreak(() => {
                next();
                if (match(SyntaxKind.minus)) {
                    return convertUnaryExpressionToNumberLiteral(disallowPrecedingLinebreak(parseUnaryExpression));
                } else {
                    return disallowPrecedingLinebreak(parseNumberLiteral);
                }
            });
        }

        const node = factory.createForStatement(counter, range, step);

        contextHandler.push(ParserContext.forStat, node);
        factory.updateForStatement(node, parseStatementUntil(() => precidateKeywords([ SyntaxKind.nextKeyword ])));
        contextHandler.remove(ParserContext.forStat);

        parseExpected(SyntaxKind.nextKeyword);

        return finishNode(node, start);
    }

    function parseForEachStatement(): ForEachStat {
        const start = getNodeStart();
        parseExpected(SyntaxKind.forKeyword);
        parseExpectedSingleLine(SyntaxKind.eachKeyword);
        const element = disallowPrecedingLinebreak(parseIdentifier);
        disallowPrecedingLinebreak(() => parseExpected(SyntaxKind.inKeyword));
        const group = parseExpressionSingleLine(false, true);

        const node = factory.createForEachStatement(element, group);

        if (group.kind !== SyntaxKind.memberExpr && group.kind !== SyntaxKind.callExpr && group.kind !== SyntaxKind.identifier) {
            raise(errorMessages.invalidGroupExpression, group);
        }

        contextHandler.push(ParserContext.forStat, node);
        factory.updateForEachStatement(node, parseStatementUntil(() => precidateKeywords([ SyntaxKind.nextKeyword ])));
        contextHandler.remove(ParserContext.forStat);

        parseExpected(SyntaxKind.nextKeyword);
        return finishNode(node, start);
    }

    function parseForLikeStatement(): ForStat | ForEachStat {
        if (lookAhead(() => next() === SyntaxKind.eachKeyword)) {
            return parseForEachStatement();
        }
        return parseForStatement();
    }

    function parseDoStatement(): DoStat {
        const start = getNodeStart();
        parseExpected(SyntaxKind.doKeyword);
        let preCondition = matchOne([ SyntaxKind.whileKeyword, SyntaxKind.untilKeyword ]);
        let condition: Expression = createMissingExpression(start);
        let until: Token<SyntaxKind.untilKeyword> | undefined = undefined;
        // Do [{While | Until} expression]
        //   [statements]
        //   [Exit Do]
        //   [statements]
        // Loop
        if (preCondition) {
            if (match(SyntaxKind.untilKeyword)) {
                until = parseExpectedNode<Token<SyntaxKind.untilKeyword>>(SyntaxKind.untilKeyword);
            }
            else {
                parseExpectedSingleLine(SyntaxKind.whileKeyword);
            }
            condition = parseExpressionSingleLine(false, true);
        }
        const node = factory.createDoStatement(condition, preCondition, until) as Mutable<DoStat>;

        contextHandler.push(ParserContext.doStat, node);
        factory.updateDoStatement(node, parseStatementUntil(() => precidateKeywords([ SyntaxKind.loopKeyword ], true, preCondition)));
        contextHandler.remove(ParserContext.doStat);

        parseExpected(SyntaxKind.loopKeyword);

        // Do
        //   [statements]
        //   [Exit Do]
        //   [statements]
        // Loop [{While | Until} expression]
        if (!preCondition) {
            if (match(SyntaxKind.untilKeyword)) {
                until = disallowPrecedingLinebreak(() => parseExpectedNode<Token<SyntaxKind.untilKeyword>>(SyntaxKind.untilKeyword));
                factory.updateDoStatement(node, until);
            }
            else {
                parseExpectedSingleLine(SyntaxKind.whileKeyword);
            }
            condition = parseExpressionSingleLine(false, true);
            factory.updateDoStatement(node, condition);
        }

        return finishNode(node, start);
    }

    function parseWhileStatement(): WhileStat {
        const start = getNodeStart();
        // While  expression
        //   [statements]
        // End While
        parseExpected(SyntaxKind.whileKeyword);
        const condition = parseExpressionSingleLine(false, true);
        const node = factory.createWhileStatement(condition);
        contextHandler.push(ParserContext.whileStat, node);
        factory.updateWhileStatement(node, parseStatementUntil(() => precidateKeywords([ SyntaxKind.endKeyword ], false, false)));
        contextHandler.remove(ParserContext.whileStat);
        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.whileKeyword, declare: false } ]);
        return finishNode(node, start);
    }

    function parseSelectCaseComparisonOperator(): Token<ComparisonPunctuationFlags> {
        switch (currentToken) {
            case SyntaxKind.equal:
                return parseTokenNode<Token<SyntaxKind.equal>>();
            case SyntaxKind.less:
                return parseTokenNode<Token<SyntaxKind.less>>();
            case SyntaxKind.lessEqual:
                return parseTokenNode<Token<SyntaxKind.lessEqual>>();
            case SyntaxKind.greater:
                return parseTokenNode<Token<SyntaxKind.greater>>();
            case SyntaxKind.greaterEqual:
                return parseTokenNode<Token<SyntaxKind.greaterEqual>>();
            case SyntaxKind.notEqual:
                return parseTokenNode<Token<SyntaxKind.notEqual>>();
        }
        return createMissingNode<Token<SyntaxKind.equal>>(SyntaxKind.equal, false, errorMessages.unexpectedToken, "=/>/>=/</<=/<>");
    }

    function parseSelectCaseComparisonExpression(): SelectCaseComparison {
        const start = getNodeStart();
        const operator = disallowPrecedingLinebreak(parseSelectCaseComparisonOperator);
        const right = parseExpressionSingleLine(false, true);
        return finishNode(factory.createSelectCaseComparisonExpression(operator, right), start);
    }

    function parseSelectCaseClauseConditions(): NodeArray<SelectCaseCondition> {
        const start = getNodeStart();
        const conditions: Expression[] = [];
        while (true) {
            switch (currentToken) {
                case SyntaxKind.equal:
                case SyntaxKind.less:
                case SyntaxKind.lessEqual:
                case SyntaxKind.greater:
                case SyntaxKind.greaterEqual:
                case SyntaxKind.notEqual:
                    conditions.push(parseSelectCaseComparisonExpression());
                    break;

                default:
                    conditions.push(parseExpressionSingleLine(false, true));
                    break;
            }

            if (hasPrecedingLinebreak() || match(SyntaxKind.eof)) {
                break;
            }

            parseExpectedSingleLine(SyntaxKind.comma);
        }
        return createNodeArray(conditions, start);
    }

    function parseSelectCaseClause(): SelectCaseClause {
        const start = getNodeStart();
        parseExpected(SyntaxKind.caseKeyword);
        const caseElse = parseOptional(SyntaxKind.elseKeyword, false, true);
        const node = factory.createSelectCaseClause(caseElse);
        contextHandler.push(ParserContext.selectClauses, node);
        let conditions = createNodeArray<SelectCaseCondition>([], getNodeStart());
        if (!caseElse) {
            conditions = parseSelectCaseClauseConditions();
        }
        const body = parseStatementUntil(() => precidateKeywords([ SyntaxKind.endKeyword, SyntaxKind.caseKeyword ], false, false));
        factory.updateSelectCaseClause(node, caseElse, ...conditions);
        factory.updateSelectCaseClause(node, body);
        contextHandler.remove(ParserContext.selectClauses);
        return finishNode(node, start);
    }

    function parseSelectStatement(): SelectStat {
        const start = getNodeStart();
        parseExpected(SyntaxKind.selectKeyword);
        parseExpectedSingleLine(SyntaxKind.caseKeyword);
        const testExpression = parseExpressionSingleLine(false, true);
        const clauses = factory.createNodeArray<SelectCaseClause>();
        const node = factory.createSelectStatement(testExpression, clauses);
        contextHandler.push(ParserContext.selectStat, node);
        while (true) {
            factory.updateNodeArray(clauses, requirePrecedingLinebreak(parseSelectCaseClause));
            if (matchOne([ SyntaxKind.endKeyword, SyntaxKind.eof ])) {
                break;
            }
        }
        contextHandler.remove(ParserContext.selectStat);
        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.selectKeyword, declare: false } ]);
        return finishNode(factory.updateSelectStatement(node, clauses), start);
    }

    function parseWithStatement(): WithStat {
        const start = getNodeStart();
        parseExpected(SyntaxKind.withKeyword);
        let object: MemberExpressionObject;
        let expr: Expression;
        if (contextHandler.test(ParserContext.withStat)) {
            let parentWith = currentWithStatement();
            expr = parseIdentifierOrHeigher(parentWith?.object);
        }
        else {
            expr = parseExpression(false, true);
        }
        if (expr.isExpression<MemberExpr>(SyntaxKind.memberExpr) ||
            expr.isExpression<CallExpr>(SyntaxKind.callExpr) ||
            expr.isExpression<IndexExpr>(SyntaxKind.indexExpr) ||
            expr.isIdentifier()) {
            object = expr;
        }
        else {
            raise(errorMessages.invalidExpression, expr);
            object = createMissingNode<Identifier>(SyntaxKind.identifier);
        }
        const statement = factory.createWithStatement(object);
        contextHandler.push(ParserContext.withStat, statement);
        factory.updateWithStatement(statement, parseStatementUntil(() => precidateKeywords([ SyntaxKind.endKeyword ], false, false)));
        contextHandler.remove(ParserContext.withStat);
        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.withKeyword, declare: false } ]);
        return finishNode(statement, start);
    }

    function currentWithStatement(): WithStat | undefined {
        return contextHandler.getContextNode(ParserContext.withStat) as WithStat;
    }

    // Section label
    //   statements
    // End Section
    function parseSectionStatement(): SectionStat {
        const start = getNodeStart();
        parseExpected(SyntaxKind.sectionKeyword);
        let label = parseExpressionSingleLine(false, false);
        if (!label.isIdentifier()) {
            raise(errorMessages.invalidSectionLabel, label);
            label = createMissingNode<Identifier>(SyntaxKind.identifier);
        }

        const node = factory.createSectionStatement(label as Identifier);
        contextHandler.push(ParserContext.section, node);
        factory.updateSectionStatement(node, undefined, parseStatementUntil(() => precidateKeywords([ SyntaxKind.endKeyword ], false, false)));
        contextHandler.remove(ParserContext.section);
        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.sectionKeyword, declare: false } ]);
        return finishNode(node, start);
    }

    // Event(name [, "description"])
    //    ...
    // End Event
    function parseEventSection(): EventSection {
        const start = getNodeStart();
        const event = parseExpectedNode<KeywordToken<SyntaxKind.eventKeyword>>(SyntaxKind.eventKeyword);
        if (fileFlag !== FileKind.dms) {
            raise(errorMessages.eventSectionCanOnlyUseInDmsFile, event);
        }
        parseExpectedSingleLine(SyntaxKind.openParenthesis);
        contextHandler.push(ParserContext.paren);
        const name = disallowPrecedingLinebreak(parseIdentifier);
        const flag = getEventSectionFlag(name.text);
        if (flag === EventSectionKind.none) {
            raise(errorMessages.invalidEventSectionName, name);
        }
        let description: StringLiteral | undefined = undefined;
        if (parseOptional(SyntaxKind.comma, false, true)) {
            description = disallowPrecedingLinebreak(() => parseExpectedNode(SyntaxKind.stringLiteral, parseStringLiteral, undefined, "字符串"));
        }
        contextHandler.remove(ParserContext.paren);
        parseExpectedSingleLine(SyntaxKind.closeParenthesis);

        const node = factory.createEventSection(name, description);
        contextHandler.push(ParserContext.eventSection, node);

        const functions: FunctionDeclaration[] = [];
        const statement = parseStatementUntil(
            () => precidateKeywords([ SyntaxKind.endKeyword ], false, false),
            stat => {
                if (stat.isDeclaration<FunctionDeclaration>(SyntaxKind.funcDecl)) {
                    functions.push(stat);
                }
            },
            true
        );
        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.eventKeyword, declare: false } ]);

        factory.updateEventSection(node, undefined, undefined, statement);
        factory.updateNodeArray(node.functions, ...functions);

        contextHandler.remove(ParserContext.eventSection);

        sectionNodes.push(node);
        return finishNode(node, start);
    }

    // Routing(Context)
    // ...
    // End Routing
    function parseRoutingSection(): RoutingSection {
        const start = getNodeStart();
        const token = parseExpectedNode<Token<SyntaxKind.routingKeyword>>(SyntaxKind.routingKeyword);
        const name = converter.convertNodeToIdentifier(token);

        let context: Identifier;
        parseExpected(SyntaxKind.openParenthesis);
        contextHandler.push(ParserContext.paren);
        if (match(SyntaxKind.paper)) {
            let kw = parseExpectedNode<Token<SyntaxKind.paper>>(SyntaxKind.paper);
            context = converter.convertNodeToIdentifier(kw);
        }
        else {
            context = parseExpectedNode<Identifier>(SyntaxKind.identifier, parseIdentifierName, errorMessages.unexpectedToken, "标识符");
        }
        contextHandler.remove(ParserContext.paren);
        parseExpected(SyntaxKind.closeParenthesis);

        if (stringToUserContext(context.text.trim()) === undefined) {
            raise(errorMessages.invalidMetadataUserContext, context, context.text.trim());
        }

        const node = factory.createRoutingSection(name, context);
        contextHandler.push(ParserContext.routingSection, node);

        let functions = node.functions as MutableNodeArray<FunctionDeclaration>;
        let stat = parseStatementUntil(
            () => precidateKeywords([ SyntaxKind.endKeyword ], false, false),
            stat => {
                if (stat.isDeclaration<FunctionDeclaration>(SyntaxKind.funcDecl)) {
                    functions.push(stat);
                }
            },
            true
        );
        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.routingKeyword, declare: false } ]);

        factory.updateRoutingSection(node, undefined, undefined, stat);
        contextHandler.remove(ParserContext.routingSection);
        sectionNodes.push(node);

        return finishNode(node, start);
    }

    // Job(name [, "description"])
    //      [TempDirectory = "<Temp Directory>"]
    // End Job
    function parseJobSection(): JobSection {
        const start = getNodeStart();
        parseExpected(SyntaxKind.jobKeyword);
        parseExpectedSingleLine(SyntaxKind.openParenthesis);
        contextHandler.push(ParserContext.paren);
        const name = parseIdentifierName();
        let description: StringLiteral | undefined;
        if (parseOptional(SyntaxKind.comma)) {
            description = disallowPrecedingLinebreak(() => parseExpectedNode<StringLiteral>(SyntaxKind.stringLiteral, parseStringLiteral, undefined, "字符串"));
        }
        contextHandler.remove(ParserContext.paren);
        parseExpectedSingleLine(SyntaxKind.closeParenthesis);
        let tempDirectory: AssignmentExpression | undefined;
        if (!match(SyntaxKind.endKeyword)) {
            const expr = parseExpression(true, false);
            if (!expr.isAssignmentExpression()) {
                raise(errorMessages.invalidExpression, expr);
            }
            else {
                const left = expr.left;
                if (!(left.isIdentifier() && left.text.toLowerCase() === "tempdirectory")) {
                    raise(errorMessages.unexpectedToken, left, "TempDirectory");
                }
                else {
                    tempDirectory = expr;
                }
            }
        }
        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.jobKeyword, declare: false } ]);
        return finishNode(factory.createJobSection(name, description, tempDirectory), start);
    }

    function parseAssignmentExpressionInsideSection(): AssignmentExpression[] {
        const expressions: AssignmentExpression[] = [];
        if (match(SyntaxKind.ppIncludeKeyword)) {
            const inc = parsePreprocessorIncludeStatement();
            if (inc.targetFile) {
                let incHasError = false;
                for (const statement of inc.targetFile.statements) {
                    if (statement.isStatement<ExprStat>(SyntaxKind.exprStat) && statement.expression.isAssignmentExpression()) {
                        expressions.push(statement.expression);
                    }
                    else {
                        incHasError = true;
                    }
                }
                if (incHasError) {
                    raise(errorMessages.illInclude, inc);
                }
            }
        }
        else {
            const element = parseExpression(true, false);
            if (element.isAssignmentExpression()) {
                expressions.push(element);
            }
            else {
                raise(errorMessages.invalidExpression, element);
            }
        }
        return expressions;
    }

    // InputDataSource(name [", description"])
    //    ConnectionString = "<connection_string>"
    //    [SelectQuery = "<select_query>"]
    //    [UpdateQuery = "<update_query>"]
    //    [UseInputAsOutput = True | False"]
    //    [JoinKey = "<variable_name>"]
    //    [JoinType = "Full" | "Inner" | "Left"]
    //    [JoinKeySorted = True | False"]
    // End InputDataSource
    function parseInputDataSourceSection(): InputDataSourceSection {
        const start = getNodeStart();
        parseExpected(SyntaxKind.inputDataSourceKeyword);
        parseExpectedSingleLine(SyntaxKind.openParenthesis);
        contextHandler.push(ParserContext.paren);
        const name = parseIdentifierName();
        let description: StringLiteral | undefined;
        if (parseOptional(SyntaxKind.comma)) {
            description = disallowPrecedingLinebreak(() => parseExpectedNode<StringLiteral>(SyntaxKind.stringLiteral, parseStringLiteral));
        }
        contextHandler.remove(ParserContext.paren);
        parseExpectedSingleLine(SyntaxKind.closeParenthesis);
        // members
        let connectionString: AssignmentExpression | undefined;
        let selectQuery: AssignmentExpression | undefined;
        let updateQuery: AssignmentExpression | undefined;
        let useInputAsOutput: AssignmentExpression | undefined;
        let joinKey: AssignmentExpression | undefined;
        let joinType: AssignmentExpression | undefined;
        let joinKeySorted: AssignmentExpression | undefined;
        while (true) {
            if (matchOne([ SyntaxKind.endKeyword, SyntaxKind.eof ])) {
                break;
            }
            const exprs = parseAssignmentExpressionInsideSection();
            for (let i = 0; i < exprs.length; i++) {
                const expr = exprs[i];
                switch (expr.left.text.toLowerCase()) {
                    case "connectionstring":
                        connectionString = expr;
                        break;
                    case "selectquery":
                        selectQuery = expr;
                        break;
                    case "updatequery":
                        updateQuery = expr;
                        break;
                    case "useinputasoutput":
                        useInputAsOutput = expr;
                        break;
                    case "joinkey":
                        joinKey = expr;
                        break;
                    case "jointype":
                        let str: StringLiteral;
                        if (!expr.right.isStringLiteral() || ((str = expr.right) && !["full", "inner", "left"].find(e => e === str.text.toLowerCase()))) {
                            raise(errorMessages.unexpectedToken, expr.right, "'Full' | 'Inner' | 'Left'");
                        }
                        else {
                            joinKey = expr;
                        }
                        break;
                    case "joinkeysorted":
                        if (expr.right.isBooleanLiteral()) {
                            joinKeySorted = expr;
                        }
                        else {
                            raise(errorMessages.unexpectedToken, expr.right, "'True' | 'False'");
                        }
                        break;
                    default:
                        raise(errorMessages.invalidExpression, expr);
                        break;
                }
            }
        }
        // 补充丢失的链接字符串
        if (!connectionString) {
            raise(errorMessages.lostNecessarySectionMember, name, "ConnectionString");
            connectionString = createMissingNode<AssignmentExpression>(SyntaxKind.binaryExpr, false);
        }
        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.inputDataSourceKeyword, declare: false } ]);
        return finishNode(factory.createInputDataSourceSection(name, description, connectionString, selectQuery, updateQuery, useInputAsOutput, joinKey, joinType, joinKeySorted), start);
    }

    // OutputDataSource(name [, "description"])
    //    [ConnectionString = "<connection_string> | UseInputAsOutput = True|False"]
    //    [MetaDataOutputName = "<metadata_location>"]
    //    [UpdateQuery = "<update_query>"]
    //    [TableOutputName = "<table_output_name>"]
    //    [VariableOrder = "SELECTORDER"]
    // End OutputDataSource
    function parseOutputDataSourceSection(): OutputDataSourceSection {
        const start = getNodeStart();
        parseExpected(SyntaxKind.outputDataSourceKeyword);
        parseExpectedSingleLine(SyntaxKind.openParenthesis);
        contextHandler.push(ParserContext.paren);
        const name = parseIdentifierName();
        let description: StringLiteral | undefined;
        if (parseOptional(SyntaxKind.comma)) {
            description = parseExpectedNode<StringLiteral>(SyntaxKind.stringLiteral, parseStringLiteral);
        }
        contextHandler.remove(ParserContext.paren);
        parseExpectedSingleLine(SyntaxKind.closeParenthesis);
        // members
        let connectionString: AssignmentExpression | undefined;
        let metadataOutputName: AssignmentExpression | undefined;
        let updateQuery: AssignmentExpression | undefined;
        let tableOutputName: AssignmentExpression | undefined;
        let variableOrder: AssignmentExpression | undefined;
        while (true) {
            if (matchOne([ SyntaxKind.endKeyword, SyntaxKind.eof ])) {
                break;
            }
            let exprs = parseAssignmentExpressionInsideSection();
            for (const expr of exprs) {
                switch (expr.left.text.toLowerCase()) {
                    case "connectionstring":
                        connectionString = expr;
                        break;
                    case "metadataoutputname":
                        metadataOutputName = expr;
                        break;
                    case "updatequery":
                        updateQuery = expr;
                        break;
                    case "tableoutputname":
                        tableOutputName = expr;
                        break;
                    case "variableorder":
                        variableOrder = expr;
                        break;
                    default:
                        raise(errorMessages.invalidExpression, expr);
                        break;
                }
            }
        }
        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.outputDataSourceKeyword, declare: false } ]);
        return finishNode(factory.createOutputDataSourceSection(name, description, connectionString, metadataOutputName, updateQuery, tableOutputName, variableOrder), start);
    }

    // GlobalSQLVariables(name [, "description"])
    //    ConnectionString = "<connection_string>"
    //    SelectQuery = "<select_query>"
    // End GlobalSQLVariables
    function parseGlobalSQLVariablesSection(): GlobalSQLVariablesSection {
        const start = getNodeStart();
        parseExpected(SyntaxKind.globalSQLVariablesKeyword);
        parseExpectedSingleLine(SyntaxKind.openParenthesis);
        contextHandler.push(ParserContext.paren);
        const name = parseIdentifierName();
        let description: StringLiteral | undefined;
        if (parseOptional(SyntaxKind.comma)) {
            description = parseExpectedNode<StringLiteral>(SyntaxKind.stringLiteral, parseStringLiteral);
        }
        contextHandler.remove(ParserContext.paren);
        parseExpectedSingleLine(SyntaxKind.closeParenthesis);
        let connectionString: AssignmentExpression | undefined;
        let selectQuery: AssignmentExpression | undefined;
        while (true) {
            if (matchOne([ SyntaxKind.endKeyword, SyntaxKind.eof ])) {
                break;
            }
            let exprs = parseAssignmentExpressionInsideSection();
            for (const expr of exprs) {
                switch (expr.left.text.toLowerCase()) {
                    case "connectionstring":
                        connectionString = expr;
                        break;
                    case "selectquery":
                        selectQuery = expr;
                        break;
                    default:
                        raise(errorMessages.invalidExpression, expr);
                        break;
                }
            }
        }
        // 补全缺少的成员
        let lostMemberName: string[] = [];
        if (!connectionString) {
            lostMemberName.push("ConnectionString");
            connectionString = createMissingNode<AssignmentExpression>(SyntaxKind.binaryExpr, false);
        }
        if (!selectQuery) {
            lostMemberName.push("SelectQuery");
            selectQuery = createMissingNode<AssignmentExpression>(SyntaxKind.binaryExpr, false);
        }
        if (lostMemberName.length > 0) {
            raise(errorMessages.lostNecessarySectionMember, name, lostMemberName.join(","));
        }
        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.globalSQLVariablesKeyword, declare: false } ]);
        return finishNode(factory.createGlobalSQLVariablesSection(name, description, connectionString, selectQuery), start);
    }

    //function checkMaybeLanguage(expression: Expression): MetadataLanguage {
    //    let language: MetadataLanguage | undefined;
    //    // 检查短编码
    //    if (isIdentifier(expression)) {
    //        language = shortCodeTextToMetadataLanguage(expression.text.trim());
    //        if (!language) {
    //            raise(errorMessages.invalidMetadataLanguage, expression);
    //        }
    //    }
    //    // 检查长编码
    //    else {
    //        language = longCodeTextToMetadataLanguage(expression.text.trim());
    //        if (!language) {
    //            raise(errorMessages.invalidMetadataLanguage, expression);
    //        }
    //    }
    //    return language ?? _defaultLanguage;
    //}

    // Metadata [(language [, context [, labeltype] [, datasource]])]
    //       field_name "field description" <type_info>;
    //       ...
    // END Metadata
    function parseMetadataSection(): MetadataSection {
        const start = getNodeStart();
        const name = converter.convertNodeToIdentifier(parseTokenNode<Token<SyntaxKind.metadataKeyword>>());
        // 可选的头部参数
        let language: Expression | undefined;
        let context: Expression | undefined;
        let labelType: Expression | undefined;
        let dataSource: Expression | undefined;
        //
        let metadataLanguage = _defaultLanguage;
        // (
        if (parseOptional(SyntaxKind.openParenthesis)) {
            contextHandler.push(ParserContext.paren);
            // language
            language = parseExpression(false, false);
            //metadataLanguage = checkMaybeLanguage(language);
            // language, context
            if (parseOptional(SyntaxKind.comma)) {
                context = parseExpression(false, false);
            }
            // language, context, labeltype
            if (parseOptional(SyntaxKind.comma)) {
                labelType = parseExpression(false, false);
            }
            // language, context, labeltype, dataSource
            if (parseOptional(SyntaxKind.comma)) {
                dataSource = parseExpression(false, false);
            }
            contextHandler.remove(ParserContext.paren);
            parseExpected(SyntaxKind.closeParenthesis);
        }
        let metadataContext = context ? (stringToUserContext(context.text.trim()) ?? DefaultOptions.scriptOptions.defaultMetadataContext) : DefaultOptions.scriptOptions.defaultMetadataContext;
        let metadataLabel = labelType? (stringToLabelType(labelType.text.trim()) ?? DefaultOptions.scriptOptions.defaultMetadataLabelType) : DefaultOptions.scriptOptions.defaultMetadataLabelType;
        // metadata
        const node = factory.createMetadataSection(name, undefined, language, context, labelType, dataSource);
        sectionNodes.push(node);
        contextHandler.push(ParserContext.metadataSection, node);
        let document = parseMetadataDocument(metadataLanguage, metadataContext, metadataLabel);
        (node as Mutable<MetadataSection>).document = document;
        node.asChildren(document);
        contextHandler.remove(ParserContext.metadataSection);
        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.metadataKeyword, declare: false } ]);
        return finishNode(node, start);
    }

    // Logging(name [, "description"])
    //    Group = "Group"
    //    Path = "Path"
    //    Alias = "Alias"
    //    [FileSize = FileSize
    // End Logging
    function parseLoggingSection(): LoggingSection {
        const start = getNodeStart();
        parseExpected(SyntaxKind.loggingKeyword);
        parseExpectedSingleLine(SyntaxKind.openParenthesis);
        contextHandler.push(ParserContext.paren);
        const name = parseIdentifierName();
        let description: StringLiteral | undefined;
        if (parseOptional(SyntaxKind.comma)) {
            description = parseExpectedNode<StringLiteral>(SyntaxKind.stringLiteral);
        }
        contextHandler.remove(ParserContext.paren);
        parseExpected(SyntaxKind.closeParenthesis);
        let group: AssignmentExpression | undefined;
        let path: AssignmentExpression | undefined;
        let alias: AssignmentExpression | undefined;
        let fileSize: AssignmentExpression | undefined;
        while (true) {
            if (matchOne([ SyntaxKind.endKeyword, SyntaxKind.eof ])) {
                break;
            }
            let exprs = parseAssignmentExpressionInsideSection();
            for (const expr of exprs) {
                switch (expr.left.text.toLowerCase()) {
                    case "group":
                        group = expr;
                        break;
                    case "path":
                        path = expr;
                        break;
                    case "alias":
                        alias = expr;
                        break;
                    case "filesize":
                        if (expr.right.isNumberLiteral()) {
                            fileSize = expr;
                        }
                        else {
                            raise(errorMessages.unexpectedToken, expr, "数字");
                        }
                        break;
                    default:
                        raise(errorMessages.invalidExpression, expr);
                        break;
                }
            }
        }
        parseKeywords([ { keyword: SyntaxKind.endKeyword, declare: false }, { keyword: SyntaxKind.loggingKeyword, declare: false } ]);
        // 检查必须的成员
        let lostMembers: string[] = [];
        if (!group) {
            lostMembers.push("Group");
            group = createMissingNode<AssignmentExpression>(SyntaxKind.binaryExpr, false);
        }
        if (!path) {
            lostMembers.push("Path");
            path = createMissingNode<AssignmentExpression>(SyntaxKind.binaryExpr, false);
        }
        if (!alias) {
            lostMembers.push("Alias");
            alias = createMissingNode<AssignmentExpression>(SyntaxKind.binaryExpr, false);
        }
        if (lostMembers.length > 0) {
            raise(errorMessages.lostNecessarySectionMember, name, lostMembers.join(","));
        }
        return finishNode(factory.createLoggingSection(name, description, group, path, alias, fileSize), start);
    }

    // preprocessor

    function parsePreprocessorDefinitionElement(parameters: PPDefineParameter[]): Node {
        const start = getNodeStart();
        // #
        if (match(SyntaxKind.unknown)) {
            let param: PPDefineParameter | undefined;
            // #identifier
            if (parameters.length > 0 &&
                scanner.getTokenText() === "#" &&
                lookAhead(() => {
                    return nextAnd(() => {
                        return (match(SyntaxKind.identifier, false) || isAllowedIdentifier()) &&
                            (param = parameters.find(p => p.name.text === scanner.getTokenText()));
                    });
                })
            ) {
                factory.updatePreprocessorDefineParameter(param!, true);
                parsingDiagnostics.pop();
                next();
                return finishNode(factory.createPreprocessorDefineStringizer(parseIdentifier()), start);
            }
            else {
                const missingNode = factory.createToken(SyntaxKind.unknown) as Mutable<Token<SyntaxKind.unknown>>;
                missingNode.text = scanner.getTokenText();
                next();
                return finishNode(missingNode, start);
            }
        }
        else if (match(SyntaxKind.identifier)) {
            const textArray = scanner.getTokenText().split("##");
            const start = getNodeStart();
            if (parameters.length === 0 || textArray.length === 1 || (textArray.length === 2 && textArray[1] === "")) {
                return parseIdentifier();
            }
            // a##b##c##...
            else {
                parseIdentifier();
                let elementStart = start;
                const identifiers: Identifier[] = [];
                for (let i = 0; i < textArray.length; i++) {
                    let element: string;
                    if (i === textArray.length - 2 && textArray[textArray.length - 1] === "") {
                        element = textArray[textArray.length - 2] + "##";
                        i++;
                    }
                    else {
                        element = textArray[i];
                        let parameter = parameters.find(e => e.name.text === element);
                        if (parameter) {
                            factory.updatePreprocessorDefineParameter(parameter, undefined, true);
                        }
                    }
                    let tempStart = start + element.length + 2;
                    let trimText = element.trim();
                    identifiers.push(finishNode(factory.createIdentifier(trimText), elementStart, elementStart + trimText.length));
                    elementStart = tempStart;
                }
                return finishNode(factory.createPreprocessorDefineTokenPaster(identifiers), start);
            }
        }
        else if (isLiteralToken(currentToken)) {
            return parseLiteralToken();
        }
        // else if (currentToken === SyntaxFlag.openParenthesis) {
        //     if (!lookAhead(() => nextAnd(() => hasPrecedingLinebreak()))) {
        //         return parseExpressionSingleLine(true, true);
        //     }
        //     return parseTokenNode<Punctuation<SyntaxFlag.openParenthesis>>();
        // }
        else if (isPunctuationToken(currentToken)) {
            return parseTokenNode<Punctuation<PunctuationKind>>();
        }

        return parseTokenNode();
    }

    /**
     *  预处理器的 `#define` 命令，只单纯完成内容替换，不涉及内容计算，但是解析器需要能够进行计算以便于提供必要的提示。
     *  + `#define identifier [ value... ]` - 不含参数
     *  + `#define identifier(param1 [, param2...]) [ value ... ]` - 含有参数
     * @returns
     */
    function parsePreprocessorDefineStatement(): PPDefine {
        const start = getNodeStart();
        const aheadComments = getAheadComments(start);
        const scannerContext = scanner.saveState().context;
        scanner.setContext(ScannerContextType.preprocessor);
        let success = contextHandler.once(ParserContext.preprocessor | ParserContext.name, () => {
            return tryParse(() => {
                // 此处需要通过 ParserContext 控制有效名称的判断, 在预处理时, 脚本关键字允许被定义
                parseExpected(SyntaxKind.ppDefineKeyword);
                return isAllowedIdentifier() && !hasPrecedingLinebreak();
            });
        });
        if (!success) {
            parseExpected(SyntaxKind.ppDefineKeyword);
            return createMissingNode<PPDefine>(
                SyntaxKind.ppDefine,
                true,
                errorMessages.unexpectedToken,
                "宏定义命名"
            );
        }
        const name = parseIdentifierName();
        const node = factory.createPreprocessorDefineStatement(name, undefined, undefined) as Mutable<PPDefine>;
        contextHandler.push(ParserContext.preprocessor, node);
        const parameters: PPDefineParameter[] = [];
        if (parseOptional(SyntaxKind.openParenthesis)) {
            while (true) {
                if (parseOptional(SyntaxKind.closeParenthesis) || match(SyntaxKind.eof)) {
                    break;
                }
                let dotDotDot: Token<SyntaxKind.dotDotDot> | undefined = parseOptionalToken(SyntaxKind.dotDotDot);
                let param: Mutable<PPDefineParameter>;
                let name: Identifier;
                if (dotDotDot) {
                    name = converter.convertNodeToIdentifier(dotDotDot);
                }
                else if (match(SyntaxKind.identifier)) {
                    name = parseIdentifierName();
                }
                else {
                    name = converter.convertNodeToIdentifier(parseTokenNode());
                }
                param = finishNode(factory.createPreprocessorDefineParameter(name), name.start, name.end) as Mutable<PPDefineParameter>;
                param.dotDotDot = dotDotDot;
                parameters.push(param);
                if (!match(SyntaxKind.closeParenthesis)) {
                    if (dotDotDot) {
                        raise(
                            errorMessages.parameterMacroVarargsMustPlaceAtLast,
                            dotDotDot
                        );
                    }
                    parseExpected(SyntaxKind.comma);
                }
            }
        }

        if (parameters.length > 0) {
            node.parameters = factory.createNodeArray(parameters);
        }

        let definition: Node[] = [];
        const valueStart = getNodeStart();
        // #define identifier [ string | number | categorical | true | false | expression | Token... ]
        if (!hasPrecedingLinebreak()) {
            let firstValue = parsePreprocessorDefinitionElement(parameters);
            definition.push(firstValue);
            if (!hasPrecedingLinebreak()) {
                while (true) {
                    if (hasPrecedingLinebreak() || match(SyntaxKind.eof)) {
                        break;
                    }
                    definition.push(parsePreprocessorDefinitionElement(parameters));
                }
            }
        }
        node.definition = createNodeArray(definition, valueStart);
        node.valueText = scanner.getTokenText(valueStart, getStartPos());
        if (aheadComments.length > 0) {
            node.aheadComments = aheadComments;
        }
        preProDefineNodeMap.set(node.name.text, node);
        contextHandler.remove(ParserContext.preprocessor);
        scanner.setContext(scannerContext);
        return finishNode(node, start);
    }

    function parsePreprocessorUndefStatement(): PPUndef {
        const start = getNodeStart();
        const scannerContext = scanner.saveState().context;
        scanner.setContext(ScannerContextType.preprocessor);
        parseExpected(SyntaxKind.ppUndefKeyword);
        const name = parseIdentifier();
        preProDefineNodeMap.delete(name.text);
        scanner.setContext(scannerContext);
        return finishNode(factory.createPreprocessorUndefStatement(name), start);
    }

    function parsePreprocessorIncludeStatement(): PPInclude {
        const start = getNodeStart();
        const scannerContext = scanner.saveState().context;
        scanner.setContext(ScannerContextType.preprocessor);
        parseExpected(SyntaxKind.ppIncludeKeyword);
        const filePath = parseExpressionSingleLine(false, false);
        let resolvedPath = "";
        let sourceFile: SourceFile | undefined = undefined;
        if (filePath.isStringLiteral()) {
            resolvedPath = resolve(dirname(sourceFileName), filePath.text);
        }
        else if (filePath.isIdentifier() && resolveIncludeIdentifier) {
            resolvedPath = resolveIncludeIdentifier(filePath.text);
        }
        const event = contextHandler.getContextNode(ParserContext.eventSection | ParserContext.metadataSection);
        if (resolvedPath !== "") {
            let file = trySearchProgramFile(resolvedPath);
            if (existsSync(resolvedPath) && statSync(resolvedPath).isFile()) {
                const savedState = saveState();
                sourceFile = parseScriptBase(resolvedPath,
                    file ? file.content : readFileSync(resolvedPath),
                    0,
                    contextHandler.test(ParserContext.metadataSection) ? FileKind.mdd : fileFlag,
                    false);
                recoveryState(savedState);
                if (!event) {
                    references.push(sourceFile);
                }
            }
            else {
                raise(errorMessages.illInclude, filePath);
            }
        }
        const node = finishNode(factory.createPreprocessorIncludeStatement(filePath, resolvedPath, sourceFile), start);
        if (event && (event.isStatement<EventSection>(SyntaxKind.eventSection) || event.isStatement<MetadataSection>(SyntaxKind.metadataSection))) {
            (event.includes as PPInclude[]).push(node);
        }
        else {
            includeNodes.push(node);
        }
        scanner.setContext(scannerContext);
        return node;
    }

    function parsePreprocessorIfStatement(): PPIf {
        const start = getNodeStart();
        const scannerContext = scanner.saveState().context;
        scanner.setContext(ScannerContextType.preprocessor);
        let ifStart = false;
        if (match(SyntaxKind.ppElIfKeyword)) {
            parseExpected(SyntaxKind.ppElIfKeyword);
        }
        else {
            ifStart = true;
            parseExpected(SyntaxKind.ppIfKeyword);
        }
        const node = factory.createPreprocessorIfStatement(factory.createEmptyExpression(), factory.createStatement(SyntaxKind.exprStat)) as Mutable<PPIf>;
        contextHandler.push(ParserContext.preprocessor, node);
        node.condition = parseExpressionSingleLine(false, true);
        node.then = parseStatementUntil(() => precidateKeywords([ SyntaxKind.ppElIfKeyword, SyntaxKind.ppElseKeyword, SyntaxKind.ppEndIfKeyword ]));
        let elseStatement: PPIf | Statement | undefined = undefined;
        if (match(SyntaxKind.ppElIfKeyword)) {
            elseStatement = parsePreprocessorIfStatement();
        } else if (match(SyntaxKind.ppElseKeyword)) {
            node.elseKeyword = parseTokenNode<Token<SyntaxKind.ppElseKeyword>>();
            elseStatement = parseStatementUntil(() => precidateKeywords([ SyntaxKind.ppEndIfKeyword ]));
        }
        node.else = elseStatement;
        node.removceAllChildren();
        node.asChildren(node.condition, node.then, node.else);
        contextHandler.remove(ParserContext.preprocessor);
        if (ifStart) {
            parseExpected(SyntaxKind.ppEndIfKeyword);
        }
        scanner.setContext(scannerContext);
        return finishNode(node, start);
    }

    function parsePreprocessorIfDefStatement(): PPIfDef {
        const start = getNodeStart();
        const scannerContext = scanner.saveState().context;
        scanner.setContext(ScannerContextType.preprocessor);
        parseExpected(SyntaxKind.ppIfDefKeyword);
        const node = factory.createPreprocessorIfDefStatement(factory.createIdentifier(), factory.createStatement(SyntaxKind.exprStat)) as Mutable<PPIfDef>;
        contextHandler.push(ParserContext.preprocessor, node);
        let condition = parseExpressionSingleLine(false, true);
        if (condition.isIdentifier()) {
            node.macroName = condition;
        }
        else {
            node.macroName = createMissingNode<Identifier>(SyntaxKind.identifier, false);
            raise(errorMessages.unexpectedToken, "宏名");
        }
        node.then = parseStatementUntil(() => precidateKeywords([ SyntaxKind.ppElIfKeyword, SyntaxKind.ppElseKeyword, SyntaxKind.ppEndIfKeyword ]));
        let elseStatement: PPIf | Statement | undefined;
        if (match(SyntaxKind.ppElIfKeyword)) {
            elseStatement = parsePreprocessorIfStatement();
        }
        else if (match(SyntaxKind.ppElseKeyword)) {
            node.elseKeyword = parseTokenNode<Token<SyntaxKind.ppElseKeyword>>();
            elseStatement = parseStatementUntil(() => precidateKeywords([ SyntaxKind.ppEndIfKeyword ]));
        }
        node.else = elseStatement;
        node.removceAllChildren();
        node.asChildren(node.macroName, node.then, node.else);
        parseExpected(SyntaxKind.ppEndIfKeyword);
        contextHandler.remove(ParserContext.preprocessor);
        scanner.setContext(scannerContext);
        return finishNode(node, start);
    }

    function parsePreprocessorIfNDefStatement(): PPIfNDef {
        const start = getNodeStart();
        const scannerContext = scanner.saveState().context;
        scanner.setContext(ScannerContextType.preprocessor);
        parseExpected(SyntaxKind.ppIfNDefKeyword);
        const node = factory.createPreprocessorIfNDefStatement(factory.createIdentifier(), factory.createStatement(SyntaxKind.exprStat)) as Mutable<PPIfNDef>;
        contextHandler.push(ParserContext.preprocessor, node);
        let condition = parseExpressionSingleLine(false, true);
        if (condition.isIdentifier()) {
            node.macroName = condition;
        }
        else {
            node.macroName = createMissingNode<Identifier>(SyntaxKind.identifier, false);
            raise(errorMessages.unexpectedToken, "宏名");
        }
        node.then = parseStatementUntil(() => precidateKeywords([ SyntaxKind.ppElIfKeyword, SyntaxKind.ppElseKeyword, SyntaxKind.ppEndIfKeyword ]));
        let elseStatement: PPIf | Statement | undefined;
        if (match(SyntaxKind.ppElIfKeyword)) {
            elseStatement = parsePreprocessorIfStatement();
        }
        else if (match(SyntaxKind.ppElseKeyword)) {
            node.elseKeyword = parseTokenNode<Token<SyntaxKind.ppElseKeyword>>();
            elseStatement = parseStatementUntil(() => precidateKeywords([ SyntaxKind.ppEndIfKeyword ]));
        }
        node.else = elseStatement;
        node.removceAllChildren();
        node.asChildren(node.macroName, node.then, node.else);
        parseExpected(SyntaxKind.ppEndIfKeyword);
        contextHandler.remove(ParserContext.preprocessor);
        scanner.setContext(scannerContext);
        return finishNode(node, start);
    }

    function parsePreprocessorErrorStatement(): PPError {
        const start = getNodeStart();
        const scannerContext = scanner.saveState().context;
        scanner.setContext(ScannerContextType.preprocessor);
        parseExpected(SyntaxKind.ppErrorKeyword, undefined, false);
        scanner.scanToLinefeedAsString();
        const text = scanner.getTokenValue();
        scanner.setContext(scannerContext);
        next();
        return finishNode(factory.createPreprocessorErrorStatement(text), start);
    }

    function parsePreprocessorLineStatement(): PPLine {
        const start = getNodeStart();
        const scannerContext = scanner.saveState().context;
        scanner.setContext(ScannerContextType.preprocessor);
        parseExpected(SyntaxKind.ppLineKeyword);
        const sequence = parseExpectedNode<NumberLiteral>(SyntaxKind.numberLiteral, parseNumberLiteral, undefined, "整型数字");
        let location: StringLiteral | undefined = undefined;
        if (!sequence.isMissingNode() && match(SyntaxKind.stringLiteral)) {
            location = parseStringLiteral();
        }
        scanner.setContext(scannerContext);
        return finishNode(factory.createPreprocessorLineStatement(sequence, location), start);
    }

    function parseCommentReferenceFile(text: string, start: number, end: number, resolvedPath: string, file?: File): PPInclude {
        const pathNode = factory.createStringLiteral(text, LiteralType.singleLineString);
        factory.updateNode(pathNode, SyntaxKind.stringLiteral, start, end);
        const node = factory.createPreprocessorIncludeStatement(pathNode, resolvedPath) as Mutable<PPInclude>;
        node.text = text;
        let source: SourceFile | undefined;
        if (existsSync(resolvedPath) && statSync(resolvedPath).isFile()) {
            const savedState = saveState();
            source = parseScriptBase(
                resolvedPath,
                file ? file.content : readFileSync(resolvedPath),
                0,
                savedState.fileFlag
            );
            recoveryState(savedState);
        }
        else {
            raise(errorMessages.illInclude, start, end, text);
        }
        node.targetFile = source;
        return factory.updateNode<PPInclude>(node, SyntaxKind.ppInclude, start, end);
    }

    // metadata

    function currentMaybeString(): StringLiteral {
        let node: Literal | Identifier | undefined;
        switch (currentToken) {
            case SyntaxKind.stringLiteral:
                return parseStringLiteral();
            case SyntaxKind.trueKeyword:
            case SyntaxKind.falseKeyword:
            case SyntaxKind.numberLiteral:
            case SyntaxKind.nullKeyword:
            case SyntaxKind.identifier:
                node = parseLiteralToken();
            default:
                if (isReservedWord(currentToken, fileFlag)) {
                    node = parseIdentifierName();
                }
        }

        if (node) {
            return converter.convertNodeToStringLiteral(node);
        }

        return createMissingNode<StringLiteral>(SyntaxKind.stringLiteral);
    }

    function currentMustbeNumber(): NumberLiteral {
        if (match(SyntaxKind.minus)) {
            const expr = parseUnaryExpression();
            return convertUnaryExpressionToNumberLiteral(expr);
        }
        else if (match(SyntaxKind.numberLiteral)) {
            return parseNumberLiteral();
        }
        const node = createMissingNode<NumberLiteral>(SyntaxKind.numberLiteral, true, errorMessages.unexpectedToken, "数字");
        next();
        return node;
    }

    function parseLiteralOrIdentifier(): Literal | Identifier {
        if (isIdentifierOrReservedWord(currentToken)) {
            return parseIdentifierName();
        }
        return parseLiteralToken();
    }

    function parseMetadataNodeInParens<T>(parse: () => T, parseCloseParen = true): T {
        parseExpected(SyntaxKind.openParenthesis);
        const result = parse();
        if (parseCloseParen) {
            parseExpected(SyntaxKind.closeParenthesis);
        }
        return result;
    }

    function parseMetadataPropertyValue() {
        switch (currentToken) {
            case SyntaxKind.stringLiteral:
                return parseStringLiteral();
            case SyntaxKind.numberLiteral:
                return parseNumberLiteral();
            case SyntaxKind.trueKeyword:
                return parseTrueLiteral();
            case SyntaxKind.falseKeyword:
                return parseFalseLiteral();
            case SyntaxKind.nullKeyword:
                return parseNullLiteral();
            case SyntaxKind.identifier:
                return parseIdentifier();
            case SyntaxKind.minus:
                const expr = parseUnaryExpression();
                return convertUnaryExpressionToNumberLiteral(expr);
        }
        return createMissingNode<Identifier>(SyntaxKind.identifier, true, errorMessages.invalidMetadataPropertyValue);
    }

    function parseMetadataFactorLikeValue() {
        const valueNode = parseMetadataPropertyValue();
        if (valueNode.isIdentifier()) {
            return converter.convertIdentifierToStringLiteral(valueNode);
        }
        return valueNode;
    }

    // <property> ::= Name = Value
    function parseMetadataProperty(): MDMProperty {
        const start = getNodeStart();
        const name = parseIdentifierName();
        parseExpected(SyntaxKind.equal);
        const value = parseMetadataPropertyValue();
        return finishNode(factory.createMetadataProperty(name, value), start);
    }

    // <Properties> ::= ( [ AreaName: ] [ <property> (, <property> )* ] )*
    function parseMetadataProperties(areaName?: Identifier): MDMProperties {
        const start = areaName ? areaName.start : getNodeStart();
        const name = createMissingNode<Identifier>(SyntaxKind.identifier) as Mutable<Identifier>;
        name.text = "Properties";
        parseExpected(SyntaxKind.openBracket);
        const properties = parseMetadataObjectList(SyntaxKind.closeBracket, parseMetadataProperty);
        const node = factory.createMetadataProperties(name, properties, areaName);
        node.addItems(properties, true);
        return finishNode(node, start);
    }

    // [^] n1
    // [^] n1 .. n2
    // [^] n1 ..
    // .. n1
    function parseMetadataValueRange(): MDMValueRange {
        const start = getNodeStart();
        // [^] [upper] [..] [lower]
        let upperBoundary: NumberLiteral | StringLiteral | undefined;
        let lowerBoundary: NumberLiteral | StringLiteral | undefined;
        let dotDot: Token<SyntaxKind.dotDot> | undefined;
        let caret = parseOptionalToken(SyntaxKind.caret);
        let step: NumberLiteral | undefined;

        // [^] n1
        // [^] n1 .. n2
        // [^] n1 ..
        if (matchOne([ SyntaxKind.numberLiteral, SyntaxKind.stringLiteral ])) {
            lowerBoundary = match(SyntaxKind.numberLiteral) ?
                parseNumberLiteral() :
                parseStringLiteral();
            dotDot = parseOptionalToken(SyntaxKind.dotDot);
            // [^] n1 .. n2
            if (dotDot && match(SyntaxKind.numberLiteral)) {
                upperBoundary = parseNumberLiteral();
            }
            else if (dotDot && match(SyntaxKind.stringLiteral)) {
                upperBoundary = parseStringLiteral();
            }
        }
        // .. [n1]
        else if (match(SyntaxKind.dotDot)) {
            if (caret) {
                raise(errorMessages.invalidMetadataValueRange, caret);
                caret = undefined;
            }
            dotDot = parseExpectedToken(SyntaxKind.dotDot);
            if (match(SyntaxKind.numberLiteral)) {
                upperBoundary = parseNumberLiteral();
            }
            else if (match(SyntaxKind.stringLiteral)) {
                upperBoundary = parseStringLiteral();
            }
        }

        if (parseOptional(SyntaxKind.stepKeyword)) {
            step = parseExpectedNode<NumberLiteral>(SyntaxKind.numberLiteral, parseNumberLiteral);
        }

        return finishNode(factory.createMetadataValueRange(lowerBoundary, upperBoundary, step, caret, dotDot), start);
    }

    // [ [^][n1][..][n2] [step n3], ... ]
    function parseMetadataFieldValueRanges(): NodeArray<MDMValueRange> {
        const start = getNodeStart();
        parseExpected(SyntaxKind.openBracket);
        const ranges = parseMetadataObjectList(SyntaxKind.closeBracket, parseMetadataValueRange);
        // 不允许空区间'[]'
        if (ranges.length === 0) {
            raise(errorMessages.invalidMetadataValueRange);
        }
        return createNodeArray(ranges, start);
    }

    type StyleTestResult = { nameResult: boolean, valueResult: boolean };

    function checkStylePropertyValue<T>(property: MDMProperty, nameMessage: DiagnosticMessage, valueMessage: DiagnosticMessage, test: (property: MDMProperty, arg?: T) => StyleTestResult, arg?: T) {
        const testResult = test(property, arg);
        if (!testResult.nameResult) {
            raise(nameMessage, property.name, property.name.text);
        }
        if (!testResult.valueResult) {
            raise(valueMessage, property.value, property.value.text);
        }
    }

    function isCorrectStyleProperty<T>(
        property: MDMProperty,
        stringTo: (str: string) => T | undefined,
        test: (node: Node, flag: T) => boolean, arg?: T
    ): StyleTestResult {
        const flag = arg !== undefined ? arg : stringTo(property.name.text);
        let nameResult = flag !== undefined;
        let valueResult = false;
        if (flag !== undefined) {
            valueResult = test(property.value, flag);
        }
        return { nameResult, valueResult };
    }

    function parseMetadataObjectList<T>(closeToken: SyntaxKind, parse: () => T, separator: SyntaxKind = SyntaxKind.comma, allowLastSeparater: boolean = false): T[] {
        const list: T[] = [];
        while (true) {
            if (parseOptional(closeToken) || match(SyntaxKind.eof)) {
                break;
            }
            list.push(parse());
            const comma = parseOptionalToken(separator);
            if (comma && match(closeToken) && !allowLastSeparater) {
                raise(errorMessages.unexpectedComma, comma);
            }
            else if (!comma && !match(closeToken)) {
                raise(errorMessages.unexpectedToken, scanner.getStartPos(), scanner.getStartPos() + 1, tokenToString(separator));
            }
        }
        return list;
    }

    function parseMetadataStylePropertyList<T extends Node>(
        node: T,
        closeToken: SyntaxKind,
        parseProperty: (node: T) => void
    ) {
        while (true) {
            if (parseOptional(closeToken) || match(SyntaxKind.eof)) {
                break;
            }
            parseProperty(node);
            const comma = parseOptionalToken(SyntaxKind.comma);
            if (comma && match(closeToken)) {
                raise(errorMessages.unexpectedComma, comma);
            }
            else if (!comma && !match(closeToken)) {
                raise(errorMessages.unexpectedToken, scanner.getStartPos(), scanner.getStartPos() + 1, ",");
            }
        }
    }

    function parseMetadataCellStyleProperty(cellStyle: Mutable<MDMCellStyle>): void {
        const property = parseMetadataProperty();
        const flag = stringToMetadataCellStylePropertyFlag(property.name.text);
        checkStylePropertyValue(
            property,
            errorMessages.invalidMetadataCellStyleProperty,
            errorMessages.invalidMetadataPropertyValue,
            (property: MDMProperty, arg?: MDMCellStylePropertyFlags) => isCorrectStyleProperty(property, stringToMetadataCellStylePropertyFlag, testCellStylePropertyValue, arg),
            flag
        );

        switch (flag) {
            case MDMCellStylePropertyFlags.bgColor:
                cellStyle.bgColor = property;
                break;
            case MDMCellStylePropertyFlags.borderBottomColor:
                cellStyle.borderBottomColor = property;
                break;
            case MDMCellStylePropertyFlags.borderBottomStyle:
                cellStyle.borderBottomStyle = property;
                break;
            case MDMCellStylePropertyFlags.borderBottomWidth:
                cellStyle.borderBottomWidth = property;
                break;
            case MDMCellStylePropertyFlags.borderColor:
                cellStyle.borderColor = property;
                break;
            case MDMCellStylePropertyFlags.borderLeftColor:
                cellStyle.borderLeftColor = property;
                break;
            case MDMCellStylePropertyFlags.borderLeftStyle:
                cellStyle.borderLeftStyle = property;
                break;
            case MDMCellStylePropertyFlags.borderLeftWidth:
                cellStyle.borderLeftWidth = property;
                break;
            case MDMCellStylePropertyFlags.borderRightColor:
                cellStyle.borderRightColor = property;
                break;
            case MDMCellStylePropertyFlags.borderRightStyle:
                cellStyle.borderRightStyle = property;
                break;
            case MDMCellStylePropertyFlags.borderRightWidth:
                cellStyle.borderRightWidth = property;
                break;
            case MDMCellStylePropertyFlags.borderStyle:
                cellStyle.borderStyle = property;
                break;
            case MDMCellStylePropertyFlags.borderTopColor:
                cellStyle.borderTopColor = property;
                break;
            case MDMCellStylePropertyFlags.borderTopStyle:
                cellStyle.borderTopStyle = property;
                break;
            case MDMCellStylePropertyFlags.borderTopWidth:
                cellStyle.borderTopWidth = property;
                break;
            case MDMCellStylePropertyFlags.borderWidth:
                cellStyle.borderWidth = property;
                break;
            case MDMCellStylePropertyFlags.colspan:
                cellStyle.colSpan = property;
                break;
            case MDMCellStylePropertyFlags.height:
                cellStyle.height = property;
                break;
            case MDMCellStylePropertyFlags.padding:
                cellStyle.padding = property;
                break;
            case MDMCellStylePropertyFlags.paddingBottom:
                cellStyle.paddingBottom = property;
                break;
            case MDMCellStylePropertyFlags.paddingLeft:
                cellStyle.paddingLeft = property;
                break;
            case MDMCellStylePropertyFlags.paddingRight:
                cellStyle.paddingRight = property;
                break;
            case MDMCellStylePropertyFlags.paddingTop:
                cellStyle.paddingTop = property;
                break;
            case MDMCellStylePropertyFlags.repeatHeader:
                cellStyle.repeatHeader = property;
                break;
            case MDMCellStylePropertyFlags.repeatSideHeader:
                cellStyle.repeatSideHeader = property;
                break;
            case MDMCellStylePropertyFlags.rowspan:
                cellStyle.rowSpan = property;
                break;
            case MDMCellStylePropertyFlags.width:
                cellStyle.width = property;
                break;
            case MDMCellStylePropertyFlags.wrap:
                cellStyle.wrap = property;
                break;
        }
    }

    function parseMetadataCellStyle(): MDMCellStyle {
        const start = getNodeStart();
        if (lookAhead(nextTokenIsEqualAllowLinebreak)) {
            const cellStyleProperty = parseMetadataProperty();
            const valueCorrect = testCellStylePropertyValue(cellStyleProperty.value, MDMCellStylePropertyFlags.borderStyle);
            if (!valueCorrect) {
                raise(errorMessages.invalidMetadataPropertyValue, cellStyleProperty.value);
            }
            return finishNode(factory.createMetadataCellStyle(cellStyleProperty.name, [["borderStyle", cellStyleProperty]]), start);
        }

        const name = parseIdentifier();
        parseExpected(SyntaxKind.openParenthesis);

        const cellStyle = factory.createMetadataCellStyle(name, []);
        parseMetadataStylePropertyList(cellStyle, SyntaxKind.closeParenthesis, parseMetadataCellStyleProperty);
        return finishNode(cellStyle, start);
    }

    function parseMetadataFontStyleProperty(fontStyle: Mutable<MDMFontStyle>): void {
        const property = parseMetadataProperty();
        const flag = stringToMetadataFontStylePropertyFlag(property.name.text);
        checkStylePropertyValue(
            property,
            errorMessages.invalidMetadataFontStyleProperty,
            errorMessages.invalidMetadataPropertyValue,
            (property, arg) => isCorrectStyleProperty(property, stringToMetadataFontStylePropertyFlag, testFontStylePropertyValue, arg),
            flag
        );

        switch (flag) {
            case MDMFontStylePropertyFlags.family:
                fontStyle.family = property;
                break;
            case MDMFontStylePropertyFlags.isBlink:
                fontStyle.isBlink = property;
                break;
            case MDMFontStylePropertyFlags.isBold:
                fontStyle.isBold = property;
                break;
            case MDMFontStylePropertyFlags.isItalic:
                fontStyle.isItalic = property;
                break;
            case MDMFontStylePropertyFlags.isOverline:
                fontStyle.isOverline = property;
                break;
            case MDMFontStylePropertyFlags.isStrikeThrough:
                fontStyle.isStrikethrough = property;
                break;
            case MDMFontStylePropertyFlags.isSubscript:
                fontStyle.isSubscript = property;
                break;
            case MDMFontStylePropertyFlags.isSuperscript:
                fontStyle.isSuperscript = property;
                break;
            case MDMFontStylePropertyFlags.isUnderline:
                fontStyle.isUnderline = property;
                break;
            case MDMFontStylePropertyFlags.size:
                fontStyle.size = property;
                break;
        }
    }

    function parseMetadataFontStyle(): MDMFontStyle {
        const start = getNodeStart();
        if (lookAhead(nextTokenIsEqualAllowLinebreak)) {
            const fontStyleProperty = parseMetadataProperty();
            const valueCorrect = testFontStylePropertyValue(fontStyleProperty.value, MDMFontStylePropertyFlags.family);
            if (!valueCorrect) {
                raise(errorMessages.invalidMetadataPropertyValue, fontStyleProperty.value);
            }
            return finishNode(factory.createMetadataFontStyle(fontStyleProperty.name, [[ "family", fontStyleProperty ]]), start);
        }

        const name = parseIdentifier();
        parseExpected(SyntaxKind.openParenthesis);

        const fontStyle = factory.createMetadataFontStyle(name, []);
        parseMetadataStylePropertyList(fontStyle, SyntaxKind.closeParenthesis, parseMetadataFontStyleProperty);
        return finishNode(fontStyle, start);
    }

    function parseMetadataControlStyleProperty(controlStyle: Mutable<MDMControlStyle>) {
        const property = parseMetadataProperty();
        const flag = stringToMetadataControlStylePropertyFlag(property.name.text);
        checkStylePropertyValue(
            property,
            errorMessages.invalidMetadataControlStyleProperty,
            errorMessages.invalidMetadataPropertyValue,
            (property, arg) => isCorrectStyleProperty(property, stringToMetadataControlStylePropertyFlag, testControlStylePropertyValue, arg),
            flag
        );

        switch (flag) {
            case MDMControlStylePropertyFlags.accelerator:
                controlStyle.accelerator = property;
                break;
            case MDMControlStylePropertyFlags.readonly:
                controlStyle.readOnly = property;
                break;
            case MDMControlStylePropertyFlags.type:
                controlStyle.type = property;
                break;
        }

    }

    function parseMetadataControlStyle(): MDMControlStyle {
        const start = getNodeStart();
        if (lookAhead(nextTokenIsEqualAllowLinebreak)) {
            const controlStyleProperty = parseMetadataProperty();
            const valueCorrect = testControlStylePropertyValue(controlStyleProperty.value, MDMControlStylePropertyFlags.type);
            if (!valueCorrect) {
                raise(errorMessages.invalidMetadataPropertyValue, controlStyleProperty.value);
            }
            return finishNode(factory.createMetadataControlStyle(controlStyleProperty.name, [["type", controlStyleProperty]]), start);
        }

        const name = parseIdentifier();
        parseExpected(SyntaxKind.openParenthesis);

        const controlStyle = factory.createMetadataControlStyle(name, []);
        parseMetadataStylePropertyList(controlStyle, SyntaxKind.closeParenthesis, parseMetadataControlStyleProperty);
        return finishNode(controlStyle, start);
    }

    function parseMetadataStyleProperty(style: Mutable<MDMStyle>) {
        const propertyName = scanner.getTokenText().toLowerCase();
        if (propertyName === "control") {
            style.control = parseMetadataControlStyle();
        }
        else if (propertyName === "cell") {
            style.cell = parseMetadataCellStyle();
        }
        else if (propertyName === "font") {
            style.font = parseMetadataFontStyle();
        }
        else {
            const property = parseMetadataProperty();
            const flag = stringToMetadataStylePropertyFlag(property.name.text);
            checkStylePropertyValue(
                property,
                errorMessages.invalidMetadataStyleProperty,
                errorMessages.invalidMetadataPropertyValue,
                (property, arg) => isCorrectStyleProperty(property, stringToMetadataStylePropertyFlag, testStylePropertyValue, arg),
                flag
            );
            switch (flag) {
                case MDMPropertyFlags.align:
                    style.align = property;
                    break;
                case MDMPropertyFlags.bgColor:
                    style.bgColor = property;
                    break;
                case MDMPropertyFlags.color:
                    style.color = property;
                    break;
                case MDMPropertyFlags.columns:
                    style.columns = property;
                    break;
                case MDMPropertyFlags.cursor:
                    style.cursor = property;
                    break;
                case MDMPropertyFlags.elementAlign:
                    style.elementAlign = property;
                    break;
                case MDMPropertyFlags.height:
                    style.height = property;
                    break;
                case MDMPropertyFlags.hidden:
                    style.hidden = property;
                    break;
                case MDMPropertyFlags.image:
                    style.image = property;
                    break;
                case MDMPropertyFlags.imagePosition:
                    style.imagePosition = property;
                    break;
                case MDMPropertyFlags.indent:
                    style.indent = property;
                    break;
                case MDMPropertyFlags.orientation:
                    style.orientation = property;
                    break;
                case MDMPropertyFlags.rows:
                    style.rows = property;
                    break;
                case MDMPropertyFlags.verticalAlign:
                    style.verticalAlign = property;
                    break;
                case MDMPropertyFlags.width:
                    style.width = property;
                    break;
                case MDMPropertyFlags.zIndex:
                    style.zIndex = property;
                    break;
            }
        }
    }

    // <Styles> ::= ( [ AreaName: ] style ( <property> (, <property> )* ) )*
    function parseMetadataStyle(areaName?: Identifier): MDMStyle {
        const start = areaName ? areaName.start : getNodeStart();
        const name = match(SyntaxKind.mdmStyleKeyword) ?
            parseTokenNode<Token<SyntaxKind.mdmStyleKeyword>>() :
            parseTokenNode<Token<SyntaxKind.mdmLabelStyleKeyword>>();
        const fit = parseExpected(SyntaxKind.openParenthesis);
        const style = factory.createMetadataStyle(converter.convertNodeToIdentifier(name)) as Mutable<MDMStyle>;
        style.areaName = areaName;
        if (fit) {
            parseMetadataStylePropertyList(style, SyntaxKind.closeParenthesis, parseMetadataStyleProperty);
        }
        return finishNode(style, start);
    }

    function parseMetadataTemplateProperty(): MDMTemplate {
        const start = getNodeStart();
        const name = parseIdentifierName();
        parseExpected(SyntaxKind.equal);
        const value = parseMetadataPropertyValue();
        return finishNode(factory.createMetadataTemplate(name, value), start);
    }

    // <Templates> ::= ( [ AreaName: ] templates ( field_item = "filename" (, field_item = "filename" )* ) )*
    function parseMetadataTemplates(areaName?: Identifier): MDMTemplates {
        const start = areaName ? areaName.start : getNodeStart();
        const name = parseExpectedNode<Token<SyntaxKind.mdmTemplatesKeyword>>(SyntaxKind.mdmTemplatesKeyword);
        parseExpected(SyntaxKind.openParenthesis);
        const properties = parseMetadataObjectList(SyntaxKind.closeParenthesis, parseMetadataTemplateProperty);
        const node = factory.createMetadataTemplates(converter.convertNodeToIdentifier(name), properties, areaName);
        node.addItems(properties, undefined, (existObj, newObj) => {
            raise(errorMessages.duplicateMetadataTemplateName, newObj.name, existObj.name.text);
        });
        return finishNode(node, start);
    }

    function parseMetadataLabel(areaName?: Identifier): MDMLabel {
        const start = areaName ? areaName.start : getNodeStart();
        const label = match(SyntaxKind.minus) ? parseTokenNode<Token<SyntaxKind.minus>>() : parseStringLiteral();
        return finishNode(factory.createMetadataLabel(label, areaName), start);
    }

    function startMetadataLabeledObject<T extends MDMLabeledObject>(
        constructor: (name: Identifier, label?: MDMLabel) => T,
        allowMinusName: boolean = false,
        nameCallback?: () => Identifier
    ): Mutable<T> {
        let name: Identifier | undefined = undefined;
        // 优先使用回调函数
        if (nameCallback) {
            name = nameCallback();
        }
        // 默认允许将字符串转换为标识符名称，需要检查名称是否合法
        else if (match(SyntaxKind.stringLiteral)) {
            const strName = parseStringLiteral();
            name = converter.convertNodeToIdentifier(strName);
            if (!isLigalIdentifier(name.text)) {
                raise(errorMessages.illegalMetadataName, name, name.text);
            }
        }
        else if (match(SyntaxKind.minus)) {
            const minus = parseTokenNode<Token<SyntaxKind.minus>>();
            name = converter.convertNodeToIdentifier(minus);
            if (!allowMinusName) {
                raise(errorMessages.illegalMetadataName, minus, "-");
            }
        }
        else {
            name = parseIdentifierName();
        }
        // base property
        let label: MDMLabel | undefined;
        let properties: MDMProperties | undefined;
        let templates: MDMTemplates | undefined;
        let style: MDMStyle | undefined;
        let labelStyle: MDMStyle | undefined;
        // areaName
        let areaName: Identifier | undefined;
        // 只读取 [ property = value, ... ] /  template ( property, ... ) / style ( ... ) / labelstyle ( ... )
        while (true) {
            // AreaName:
            if (match(SyntaxKind.identifier) && lookAhead(nextTokenIsColonAllowLinebreak)) {
                areaName = parseIdentifierName();
                next();
            }
            // [ property ,... ]
            else if (match(SyntaxKind.openBracket)) {
                let currentProperties = parseMetadataProperties(areaName);
                if (!areaName) {
                    if (!properties) {
                        properties = currentProperties;
                    }
                    else {
                        properties.addItems(currentProperties.items, true);
                    }
                }
                else {
                    properties?.addArealObject(currentProperties, undefined, (existObject, newObject) => {
                        existObject.addItems(newObject.items, true);
                    });
                    areaName = undefined;
                }
            }
            // templates ( ... )
            else if (match(SyntaxKind.mdmTemplatesKeyword)) {
                let currentTemplates = parseMetadataTemplates(areaName);
                if (!areaName) {
                    if (!templates) {
                        templates = currentTemplates;
                    }
                    else {
                        templates.addItems(currentTemplates.items, undefined, (_, newObject) => raise(errorMessages.propertyRedeclaration, newObject, newObject.name.text));
                    }
                }
                else {
                    templates?.addArealObject(currentTemplates, undefined, (existObject, newObject) => {
                        existObject.addItems(newObject.items, undefined, (_, newObject) => raise(errorMessages.propertyRedeclaration, newObject.name, newObject.name.text));
                    });
                    areaName = undefined;
                }
            }
            // style ( ... )
            else if (match(SyntaxKind.mdmStyleKeyword)) {
                let currentStyle = parseMetadataStyle(areaName);
                if (!areaName) {
                    if (!style) {
                        style = currentStyle;
                    }
                    else {
                        style.set(currentStyle);
                    }
                }
                else {
                    style?.addArealObject(currentStyle, undefined, (existObject, newObject) => {
                        existObject.set(newObject);
                    });
                    areaName = undefined;
                }
            }
            // labelStyle ( ... )
            else if (match(SyntaxKind.mdmLabelStyleKeyword)) {
                let currentLabelStyle = parseMetadataStyle(areaName);
                if (!areaName) {
                    if (!labelStyle) {
                        labelStyle = currentLabelStyle;
                    }
                    else {
                        labelStyle.set(currentLabelStyle);
                    }
                }
                else {
                    labelStyle?.addArealObject(currentLabelStyle, undefined, (existObject, newObject) => {
                        existObject.set(newObject);
                    });
                    areaName = undefined;
                }
            }
            // "字符串" / -
            else if (match(SyntaxKind.stringLiteral) || match(SyntaxKind.minus)) {
                let currentLabel = parseMetadataLabel(areaName);
                if (!areaName) {
                    if (label !== undefined) {
                        raise(errorMessages.duplicateSpecifiedLabel, label, (name ?? label).text, label.label.text, currentLabel.label.text);
                    }
                    else {
                        label = currentLabel;
                    }
                }
                else {
                    label?.addArealObject(currentLabel, undefined, (existObject, newObject) => {
                        raise(errorMessages.duplicateSpecifiedLabel, newObject, (name ? name.text : label ? label.text : "未命名字段"), existObject.label.text, newObject.label.text);
                    });
                }
            }
            else {
                break;
            }
        }

        // 没有`name`的值时，尝试将`label`转换为`name`
        if (!name) {
            if (label) {
                name = converter.convertNodeToIdentifier(label);
                if (!isLigalIdentifier(name.text)) {
                    raise(errorMessages.illegalMetadataName, name, name.text);
                }
            }
            else {
                name = createMissingNode<Identifier>(SyntaxKind.identifier);
            }
        }

        const node = constructor(name, label) as Mutable<T>;
        node.properties = properties;
        node.templates = templates;
        node.style = style;
        node.labelStyle = labelStyle;
        return node;
    }

    // AreaName lcl ( [language] [, [user-context] [, [label-type] ]] )
    function parseMetadataAreaName() {
        const start = getNodeStart();
        const name = parseIdentifierName();
        parseExpected(SyntaxKind.mdmLCLKeyword);
        parseExpected(SyntaxKind.openParenthesis);

        let language: Expression | undefined;
        if (!match(SyntaxKind.comma)) {
            language = parseExpression(false, false);
        }
        parseExpected(SyntaxKind.comma);

        let userContext: Expression | undefined;
        if (!match(SyntaxKind.comma)) {
            userContext = parseExpression(false, false);
        }
        parseExpected(SyntaxKind.comma);

        let labelType: Expression | undefined;
        if (!match(SyntaxKind.closeParenthesis)) {
            labelType = parseExpression(false, false);
        }
        parseExpected(SyntaxKind.closeParenthesis);

        return finishNode(factory.createMetadataAreaName(name, language, userContext, labelType), start);
    }

    function parseMaybeMetadataFieldType(): { flag: MDMFieldFlags, token: Token<SyntaxKind> } {
        let flag: MDMFieldFlags = MDMFieldFlags.unknown;
        switch (currentToken) {
            case SyntaxKind.mdmLongKeyword:
                flag = MDMFieldFlags.long;
                break;
            case SyntaxKind.mdmDoubleKeyword:
                flag = MDMFieldFlags.double;
                break;
            case SyntaxKind.mdmTextKeyword:
                flag = MDMFieldFlags.text;
                break;
            case SyntaxKind.mdmDateKeyword:
                flag = MDMFieldFlags.date;
                break;
            case SyntaxKind.mdmBooleanKeyword:
                flag = MDMFieldFlags.boolean;
                break;
            case SyntaxKind.mdmCategoricalKeyword:
                flag = MDMFieldFlags.categorical;
                break;
            case SyntaxKind.mdmDefineKeyword:
                flag = MDMFieldFlags.define;
                break;
            case SyntaxKind.mdmInfoKeyword:
                flag = MDMFieldFlags.info;
                break;
            case SyntaxKind.loopKeyword:
                if (lookAhead(nextTokenIsOpenBracketaAllowLinebreak)) {
                    flag = MDMFieldFlags.numericLoop;
                }
                else {
                    flag = MDMFieldFlags.categoricalLoop;
                }
                break;
            case SyntaxKind.mdmGridKeyword:
                flag = MDMFieldFlags.grid;
                break;
            case SyntaxKind.mdmCompoundKeyword:
                flag = MDMFieldFlags.compound;
                break;
            case SyntaxKind.mdmBlockKeyword:
                flag = MDMFieldFlags.block;
                break;
            case SyntaxKind.mdmPageKeyword:
                flag = MDMFieldFlags.page;
                break;
            case SyntaxKind.mdmDBKeyword:
                flag = MDMFieldFlags.databaseQuestions;
                break;
        }
        let token = parseTokenNode<Token<SyntaxKind>>();
        return { flag, token };
    }

    function parseMetadataCategoryExpression(): MDMCategoryExpression {
        const start = getNodeStart();
        const name = parseTokenNode<Token<SyntaxKind.mdmExpressionKeyword>>();
        parseExpected(SyntaxKind.openParenthesis);
        const expression = parseExpression(false, true);
        let keyword: Token<SyntaxKind.mdmDeriveElementsKeyword | SyntaxKind.mdmNoDeriveElementsKeyword> | undefined;
        if (parseOptional(SyntaxKind.comma)) {
            if (match(SyntaxKind.mdmDeriveElementsKeyword)) {
                keyword = parseTokenNode<Token<SyntaxKind.mdmDeriveElementsKeyword>>();
            }
            else if (match(SyntaxKind.mdmNoDeriveElementsKeyword)) {
                keyword = parseTokenNode<Token<SyntaxKind.mdmNoDeriveElementsKeyword>>();
            }
            else {
                raise(errorMessages.unexpectedToken, "DerivedElements | NoDerivedElements");
                if (!match(SyntaxKind.closeParenthesis)) {
                    next();
                }
            }
        }
        parseExpected(SyntaxKind.closeParenthesis);
        return finishNode(factory.createMetadataCategoryExpression(
            converter.convertNodeToIdentifier(name),
            converter.convertNodeToStringLiteral(expression), keyword), start);
    }

    function parseMetadataCategoryElementType(): MDMCategoryElementType {
        const start = getNodeStart();
        const name = parseTokenNode<Token<SyntaxKind.mdmElementTypeKeyword>>();
        parseExpected(SyntaxKind.openParenthesis);
        let elementType: StringLiteral | Identifier;
        if (match(SyntaxKind.stringLiteral)) {
            elementType = parseStringLiteral();
        }
        else if (match(SyntaxKind.identifier)) {
            elementType = parseIdentifier();
        }
        else {
            elementType = createMissingNode<Identifier>(
                SyntaxKind.identifier,
                true,
                errorMessages.unexpectedToken,
                "AnalysisBase | AnalysisCategory | AnalysisMaximum | AnalysisMean | AnalysisMinimum | AnalysisSampleVariance | AnalysisStdDev | AnalysisStdErr | AnalysisSubHeading | AnalysisSubTotal | AnalysisSummaryData | AnalysisTotal");
        }
        parseExpected(SyntaxKind.closeParenthesis);
        return finishNode(factory.createMetadataCategoryElementType(
            converter.convertNodeToIdentifier(name),
            elementType), start);
    }

    function isMetadataSortOrderKeyword(): boolean {
        return matchOne([
            SyntaxKind.mdmRanKeyword,
            SyntaxKind.mdmRandomizeKeyword,
            SyntaxKind.mdmRotKeyword,
            SyntaxKind.mdmRotateKeyword,
            SyntaxKind.mdmRevKeyword,
            SyntaxKind.mdmReverseKeyword,
            SyntaxKind.mdmAscKeyword,
            SyntaxKind.mdmAscendingKeyword,
            SyntaxKind.mdmDescKeyword,
            SyntaxKind.mdmDescendingKeyword,
            SyntaxKind.mdmFixKeyword,
        ]);
    }

    function parseMetadataSortOrder(includeNamespace: boolean = false): MDMSortOrder & { namespace?: Token<SyntaxKind.mdmNamespaceKeyword> } {

        let rotate: Token<SyntaxKind.mdmRotKeyword> | Token<SyntaxKind.mdmRotateKeyword> | undefined;
        let randomize: Token<SyntaxKind.mdmRanKeyword> | Token<SyntaxKind.mdmRandomizeKeyword> | undefined;
        let reverse: Token<SyntaxKind.mdmRevKeyword> | Token<SyntaxKind.mdmReverseKeyword> | undefined;
        let ascending: Token<SyntaxKind.mdmAscKeyword> | Token<SyntaxKind.mdmAscendingKeyword> | undefined;
        let descending: Token<SyntaxKind.mdmDescKeyword> | Token<SyntaxKind.mdmDescendingKeyword> | undefined;
        let fix: Token<SyntaxKind.mdmFixKeyword> | undefined;
        let namespace: Token<SyntaxKind.mdmNamespaceKeyword> | undefined;

        loop: while (true) {
            switch (currentToken) {
                case SyntaxKind.mdmRotKeyword:
                case SyntaxKind.mdmRotateKeyword:
                    rotate = parseTokenNode<Token<SyntaxKind.mdmRotKeyword | SyntaxKind.mdmRotateKeyword>>();
                    break;
                case SyntaxKind.mdmRanKeyword:
                case SyntaxKind.mdmRandomizeKeyword:
                    randomize = parseTokenNode<Token<SyntaxKind.mdmRanKeyword | SyntaxKind.mdmRandomizeKeyword>>();
                    break;
                case SyntaxKind.mdmRevKeyword:
                case SyntaxKind.mdmReverseKeyword:
                    reverse = parseTokenNode<Token<SyntaxKind.mdmRevKeyword | SyntaxKind.mdmReverseKeyword>>();
                    break;
                case SyntaxKind.mdmAscKeyword:
                case SyntaxKind.mdmAscendingKeyword:
                    ascending = parseTokenNode<Token<SyntaxKind.mdmAscKeyword | SyntaxKind.mdmAscendingKeyword>>();
                    break;
                case SyntaxKind.mdmDescKeyword:
                case SyntaxKind.mdmDescendingKeyword:
                    descending = parseTokenNode<Token<SyntaxKind.mdmDescKeyword | SyntaxKind.mdmDescendingKeyword>>();
                    break;
                case SyntaxKind.mdmFixKeyword:
                    fix = parseTokenNode<Token<SyntaxKind.mdmFixKeyword>>();
                    break;
                case SyntaxKind.mdmNamespaceKeyword:
                    namespace = parseTokenNode<Token<SyntaxKind.mdmNamespaceKeyword>>();
                    if (!includeNamespace) {
                        raise(errorMessages.syntaxError, namespace, namespace.text);
                    }
                    break;
                default:
                    break loop;
            }
        }

        return { rotate, randomize, reverse, ascending, descending, fix, namespace };
    }

    function parseMetadataCategoryKeycode(): MDMKeycode {
        const start = getNodeStart();
        const name = converter.convertNodeToIdentifier(parseTokenNode<Token<SyntaxKind.mdmKeycodeKeyword>>());
        const value = parseMetadataNodeInParens(currentMaybeString);
        return finishNode(factory.createMetadataCategoryKeycode(name, value), start);
    }

    function parseMetadataCategoryFactor(): MDMFactor {
        const start = getNodeStart();
        const name = converter.convertNodeToIdentifier(parseTokenNode<Token<SyntaxKind.mdmFactorKeyword>>());
        const value = parseMetadataNodeInParens(parseMetadataFactorLikeValue);
        return finishNode(factory.createMetadataCategoryFactor(name, value), start);
    }

    function parseMetadataCategory(): MDMCategory {
        const start = getNodeStart();
        const nextIsUse = lookAhead(() => next() === SyntaxKind.mdmUseKeyword);
        // <category> ::= [ list_name ]
        //            use define_list
        //            [ "list_label" ]
        //            [ sublist [ rot[ate] | ran[domize] | rev[erse] |
        //                asc[ending] | desc[ending] ] ]
        //            [ fix ]
        if (nextIsUse || match(SyntaxKind.mdmUseKeyword)) {
            let name: Identifier | undefined;
            let listName: Identifier | undefined;
            if (nextIsUse) {
                listName = parseIdentifierName();
                name = listName;
            }
            parseExpected(SyntaxKind.mdmUseKeyword);
            const backslashBackslashDot = parseOptionalToken<SyntaxKind.backslashBackslashDot>(SyntaxKind.backslashBackslashDot);
            const labeledObject = startMetadataLabeledObject(factory.createMetadataCategorySublist, true);
            // sublist
            let sublistNode: MDMSublist | undefined;
            if (match(SyntaxKind.mdmSublistKeyword)) {
                const sublistStart = getNodeStart();
                const sublistKw = parseTokenNode<Token<SyntaxKind.mdmSublistKeyword>>();
                const sublistName = converter.convertNodeToIdentifier(sublistKw);
                sublistNode = startMetadataLabeledObject(
                    factory.createMetadataCategorySublist,
                    false,
                    () => sublistName);
                if (isMetadataSortOrderKeyword()) {
                    const sublistOrder = parseMetadataSortOrder();
                    Object.assign(sublistNode, sublistOrder);
                }
                finishNode(sublistNode, sublistStart);
            }
            const categoryUseListNode = factory.createMetadataCategory(name ?? labeledObject.name, undefined, labeledObject.name, sublistNode) as Mutable<MDMCategory>;
            categoryUseListNode.list = labeledObject.name;
            categoryUseListNode.listName = listName;
            categoryUseListNode.backslashBackslashDot = backslashBackslashDot;
            if (isMetadataSortOrderKeyword()) {
                const sublistOrder = parseMetadataSortOrder();
                Object.assign(categoryUseListNode, sublistOrder);
            }
            return finishNode(categoryUseListNode, start);
        }

        const node = startMetadataLabeledObject(factory.createMetadataCategory, true);

        // <category> ::= [ list_name ]
        //            [ "list_label" ]
        //            <categories>
        if (match(SyntaxKind.openCurly)) {
            node.categories = parseMetadataCategories();
        }
        // [ <other> | <multiplier> | DK | REF | NA ]
        // [ exclusive ]
        // [ factor (factor_value) ]
        // [ keycode ("keycode_value") ]
        // [ expression ("exp_text") ]
        // [ elementtype (type_value) ]
        // [ fix ]
        // [ nofilter ]
        else {

            loop: while (true) {

                switch (currentToken) {
                    // configs
                    case SyntaxKind.mdmFactorKeyword:
                        node.factor = parseMetadataCategoryFactor();
                        break;
                    case SyntaxKind.mdmKeycodeKeyword:
                        node.keycode = parseMetadataCategoryKeycode();
                        break;
                    case SyntaxKind.mdmElementTypeKeyword:
                        node.elementType = parseMetadataCategoryElementType();
                        break;
                    case SyntaxKind.mdmExpressionKeyword:
                        node.expression = parseMetadataCategoryExpression();
                        break;
                    // keywords
                    case SyntaxKind.mdmExclusiveKeyword:
                        node.exclusive = parseTokenNode<Token<SyntaxKind.mdmExclusiveKeyword>>();
                        break;
                    case SyntaxKind.mdmFixKeyword:
                        node.fix = parseTokenNode<Token<SyntaxKind.mdmFixKeyword>>();
                        break;
                    case SyntaxKind.mdmCanFilterKeyword:
                        node.canfilter = parseTokenNode<Token<SyntaxKind.mdmCanFilterKeyword>>();
                        break;
                    case SyntaxKind.mdmNoFilterKeyword:
                        node.nofilter = parseTokenNode<Token<SyntaxKind.mdmNoFilterKeyword>>();
                        break;
                    case SyntaxKind.mdmDKKeyword:
                        node.dk = parseTokenNode<Token<SyntaxKind.mdmDKKeyword>>();
                        break;
                    case SyntaxKind.mdmREFKeyword:
                        node.ref = parseTokenNode<Token<SyntaxKind.mdmREFKeyword>>();
                        break;
                    case SyntaxKind.mdmNAKeyword:
                        node.na = parseTokenNode<Token<SyntaxKind.mdmNAKeyword>>();
                        break;

                    case SyntaxKind.mdmOtherKeyword:
                        node.other = parseMetadataMultiplierOrOther<MDMOther>(SyntaxKind.mdmOther);
                        break;
                    case SyntaxKind.mdmMultiplier:
                        node.multiplier = parseMetadataMultiplierOrOther<MDMMultiplier>(SyntaxKind.mdmMultiplier);
                        break;

                    default:
                        break loop;
                }

            }
        }

        return finishNode(node, start);
    }

    function parseMetadataCategories(): MDMCategories {
        const start = getNodeStart();
        parseExpected(SyntaxKind.openCurly);
        const categories = parseMetadataObjectList(SyntaxKind.closeCurly, parseMetadataCategory);
        const tail = parseMetadataSortOrder(true);
        return finishNode(factory.createMetadataCategories(categories, tail, tail.namespace), start);
    }

    function parseMetadataUsageType(): MDMUsageType {
        const start = getNodeStart();
        const name = parseTokenNode<Token<SyntaxKind.mdmUsageTypeKeyword>>();
        parseExpected(SyntaxKind.openParenthesis);
        const values = parseMetadataObjectList(SyntaxKind.closeParenthesis, () => parseExpression(false, false));
        let usageFlag: MDMUsageTypeFlags = 0;
        let tempFlag: MDMUsageTypeFlags | undefined;
        for (const t of values) {
            if (t.isIdentifier()) {
                tempFlag = stringToMetadataUsageTypeFlag(t.text.trim());
                if (tempFlag !== undefined) {
                    usageFlag |= tempFlag;
                }
                else {
                    raise(errorMessages.invalidUsageType, t, t.text);
                }
            }
            else if (t.isStringLiteral()) {
                const identifiers = converter.convertStringLiteralToIdentifiers(t, ",");
                for (const id of identifiers) {
                    tempFlag = stringToMetadataUsageTypeFlag(id.text);
                    if (tempFlag !== undefined) {
                        usageFlag |= tempFlag;
                    }
                    else {
                        raise(errorMessages.invalidUsageType, id, id.text);
                    }
                }
            }
        }
        const typeValueNode = converter.convertNodesToStringLiteral(values, ",");
        return finishNode(factory.createMetadataUsageType(
            converter.convertNodeToIdentifier(name),
            typeValueNode, usageFlag), start);
    }

    // ( (use "helper_field_name") | (helper_field_name "label" variable_type) )
    function parseMetadataMultiplierOrOtherField(): StringLiteral | MDMField | undefined {
        if (match(SyntaxKind.closeParenthesis)) {
            return undefined;
        }
        // use "helper_field_name"
        if (parseOptional(SyntaxKind.mdmUseKeyword)) {
            return currentMaybeString();
        }
        return parseMetadataField();
    }

    function parseMetadataMultiplierOrOther<T extends MDMMultiplier | MDMOther>(flag: T["kind"]): T {
        const start = getNodeStart();
        let kw: Token<SyntaxKind.mdmMultiplierKeyword | SyntaxKind.mdmOtherKeyword>;
        if (flag === SyntaxKind.mdmMultiplier) {
            kw = parseTokenNode<Token<SyntaxKind.mdmMultiplierKeyword>>();
        }
        else {
            kw = parseTokenNode<Token<SyntaxKind.mdmOtherKeyword>>();
        }
        let name = converter.convertNodeToIdentifier(kw);
        let field: StringLiteral | MDMField | undefined;
        if (parseOptional(SyntaxKind.openParenthesis)) {
            field = parseMetadataMultiplierOrOtherField();
            parseExpected(SyntaxKind.closeParenthesis);
        }
        return finishNode(flag === SyntaxKind.mdmMultiplier ? factory.createMetadataCategoryMultiplier(name, field) : factory.createMetadataCategoryOther(name, field), start) as T;
    }

    function parseMetadataDeclarationValueLike<F extends MDMDeclarationKind, V>(flag: F, valueParser: () => V): MDMDeclarationValueLike<F, V> {
        const start = getNodeStart();
        const nameKwToken = parseIdentifierName();
        const value = parseMetadataNodeInParens(valueParser);
        return finishNode(factory.createMetadataDeclarationValueLike(flag, nameKwToken, value), start);
    }

    // [ precision (integer) ]
    // [ <categories> ]
    // [ <codes> ]
    // [ validation ("validation_text") ]
    // [ expression ("expression_text") ]
    // [ ( initialanswer | defaultanswer ) (text) ]
    // [ <axis> ]
    // [ <usage-type> ]
    // [ <helperfields> ]
    // [ nocasedata ]
    // [ unversioned ]
    function parseMetadataFieldTail(field: Mutable<MDMField>): void {
        loop: while (true) {
            switch (currentToken) {
                case SyntaxKind.mdmPrecisionKeyword:
                    field.precision = parseMetadataDeclarationValueLike(SyntaxKind.mdmPrecision, currentMustbeNumber);
                    break;
                case SyntaxKind.mdmCodesKeyword:
                    let useField: Identifier | undefined;
                    let codes = parseMetadataDeclarationValueLike(
                        SyntaxKind.mdmCodes,
                        () => {
                            const codesStart = getNodeStart();
                            // codes({})
                            if (match(SyntaxKind.openCurly)) {
                                const codes = parseMetadataCategories();
                                return createNodeArray(codes.elements, codesStart);
                            }
                            // codes(use variable_name)
                            else if (match(SyntaxKind.mdmUseKeyword)) {
                                parseExpected(SyntaxKind.mdmUseKeyword);
                                useField = parseIdentifierName();
                            }
                            return createNodeArray([], -1, -1);
                        }
                    ) as Mutable<MDMCodes>;
                    codes.useField = useField;
                    field.codes = codes;
                    break;
                case SyntaxKind.mdmValidationKeyword:
                    field.validation = parseMetadataDeclarationValueLike(SyntaxKind.mdmValidation, currentMaybeString);
                    break;
                case SyntaxKind.mdmExpressionKeyword:
                    field.expression = parseMetadataCategoryExpression();
                    break;
                case SyntaxKind.mdmInitialAnswerKeyword:
                    field.initialAnswer = parseMetadataDeclarationValueLike(SyntaxKind.mdmInitialAnswer, parseLiteralOrIdentifier);
                    break;
                case SyntaxKind.mdmDefaultAnswerKeyword:
                    field.defaultAnswer = parseMetadataDeclarationValueLike(SyntaxKind.mdmDefaultAnswer, parseLiteralOrIdentifier);
                    break;
                case SyntaxKind.mdmAxisKeyword:
                    field.axis = parseMetadataDeclarationValueLike(
                        SyntaxKind.mdmAxis,
                        () => parseExpectedNode<StringLiteral>(SyntaxKind.stringLiteral, parseStringLiteral, errorMessages.unexpectedToken, "字符串")
                    );
                    break;
                case SyntaxKind.mdmUsageTypeKeyword:
                    field.usageType = parseMetadataUsageType();
                    break;
                case SyntaxKind.mdmHelperFieldsKeyword:
                    const helperStart = getNodeStart();
                    const helperName = parseTokenNode<Token<SyntaxKind.mdmHelperFieldsKeyword>>();
                    const helpers = parseMetadataNodeInParens(
                        () => parseMetadataObjectList(SyntaxKind.closeParenthesis, parseMetadataField, SyntaxKind.semicolon, true),
                        false
                    );
                    field.helperFields = finishNode(
                        factory.createMetadataHelperFields(
                            converter.convertNodeToIdentifier(helperName),
                            helpers
                        ),
                        helperStart
                    );
                    break;
                case SyntaxKind.mdmNocaseDataKeyword:
                    field.noCaseData = parseTokenNode<Token<SyntaxKind.mdmNocaseDataKeyword>>();
                    break;
                case SyntaxKind.mdmUnversionedKeyword:
                    field.unversioned = parseTokenNode<Token<SyntaxKind.mdmUnversionedKeyword>>();
                    break;
                case SyntaxKind.mdmScaleKeyword:
                    field.scale = parseMetadataDeclarationValueLike(SyntaxKind.mdmScale, currentMustbeNumber);
                    break;

                default:
                    break loop;
            }
        }
    }

    function parseMetadataDBQuestionsColumn(): MDMDbQuestionsColumn {
        const start = getNodeStart();
        next();
        parseExpected(SyntaxKind.openParenthesis);

        let columnId: MDMProperty | undefined;
        let columnLabel: MDMProperty | undefined;
        let columnKeycode: MDMProperty | undefined;
        let columnFile: MDMProperty | undefined;
        let columnAnalysisValue: MDMProperty | undefined;
        let columnFixed: MDMProperty | undefined;
        let columnExclusive: MDMProperty | undefined;

        parseMetadataObjectList(SyntaxKind.closeParenthesis, () => {
            const prop = parseMetadataProperty();
            switch (prop.name.text.toLowerCase()) {
                case "id":
                    columnId = prop;
                    break;
                case "lable":
                    columnLabel = prop;
                    break;
                case "keycode":
                    columnKeycode = prop;
                    break;
                case "file":
                    columnFile = prop;
                    break;
                case "analysisvalue":
                    columnAnalysisValue = prop;
                    break;
                case "fixed":
                    columnFixed = prop;
                    break;
                case "exclusive":
                    columnExclusive = prop;
                    break;
                default:
                    raise(errorMessages.invalidMetadataDBColumnProperty, prop.name, prop.name.text);
                    break;
            }
        });

        let missingNecessaryProperties: string[] = [];
        if (!columnId) {
            missingNecessaryProperties.push("ID");
        }
        if (!columnLabel) {
            missingNecessaryProperties.push("Label");
        }

        if (missingNecessaryProperties.length > 0) {
            raise(errorMessages.lostNecessaryMetadataDbColumnProperty, start, getTextPos(), missingNecessaryProperties.join(","));
        }

        return { columnId, columnLabel, columnAnalysisValue, columnExclusive, columnFile, columnFixed, columnKeycode };
    }

    function parseMetadataDBQuestionsProperties(): MDMDbQuestionsProperties {
        const start = getNodeStart();
        parseExpected(SyntaxKind.openParenthesis);

        let connectionString: MDMProperty | undefined;
        let table: MDMProperty | undefined;
        let minAnswers: MDMProperty | undefined;
        let maxAnswers: MDMProperty | undefined;
        let sqlFilter: MDMProperty | undefined;
        let cacheTimeout: MDMProperty | undefined;
        let iteratorIDType: MDMProperty | undefined;
        let columns: MDMDbQuestionsColumn | undefined;

        parseMetadataObjectList(SyntaxKind.closeParenthesis, () => {
            if (scanner.getTokenText().toLowerCase() === "columns") {
                columns = parseMetadataDBQuestionsColumn();
            }
            else {
                const property = parseMetadataProperty();
                switch (property.name.text.toLowerCase()) {
                    case "connectionstring":
                        connectionString = property;
                        break;
                    case "table":
                        table = property;
                        break;
                    case "minanswers":
                        minAnswers = property;
                        break;
                    case "maxanswers":
                        maxAnswers = property;
                        break;
                    case "sqlfilter":
                        sqlFilter = property;
                        break;
                    case "cachetimeout":
                        cacheTimeout = property;
                        break;
                    case "iteratoridtype":
                        iteratorIDType = property;
                        break;
                }
            }
        });

        const missingNecessaryProperties: string[] = [];
        if (!connectionString) {
            missingNecessaryProperties.push("ConnectionString");
        }

        if (!table) {
            missingNecessaryProperties.push("Table");
        }

        if (!columns) {
            missingNecessaryProperties.push("Columns");
        }

        if (missingNecessaryProperties.length > 0) {
            raise(errorMessages.lostNecessaryMetadataDbProperty, start, getTextPos(), missingNecessaryProperties.join(","));
        }

        return { connectionString, table, minAnswers, maxAnswers, sqlFilter, cacheTimeout, iteratorIDType, columns };
    }

    /**
     * 读取 fields 后的内容，此处的声明对象name属性为MissingNode。
     * @returns
     */
    function parseMetadataClass(fieldsKeywordToken?: Token<SyntaxKind.mdmFieldsKeyword>): MDMClass {
        const start = getNodeStart();
        const node = startMetadataLabeledObject(factory.createMetadataClass, false, () => {
            if (fieldsKeywordToken) {
                const name = converter.convertNodeToIdentifier(fieldsKeywordToken);
                identifiers.push(name);
                return name;
            }
            const fit = match(SyntaxKind.mdmFieldsKeyword);
            const name = parseIdentifierName();
            if (!fit) {
                raise(errorMessages.unexpectedToken, name, "fields");
            }
            return name;
        });
        // items
        let types: MDMField[] = [];
        let fields: MDMField[] = [];
        let pages: MDMField[] = [];
        parseExpected(SyntaxKind.openParenthesis);
        let list = parseMetadataObjectList(SyntaxKind.closeParenthesis, parseMetadataField, SyntaxKind.semicolon, true);
        for (const item of list) {
            if (item.fieldFlag === MDMFieldFlags.define) {
                types.push(item);
            }
            else if (item.fieldFlag === MDMFieldFlags.page) {
                pages.push(item);
            }
            else {
                fields.push(item);
            }
        }
        // update
        node.types = factory.createNodeArray(types);
        node.fields = factory.createNodeArray(fields);
        node.pages = factory.createNodeArray(pages);
        node.asChildren(...node.types, ...node.fields, ...node.pages);
        return finishNode(node, start);
    }

    // 和一般元数据列表一样，';'是多个变量之间的分隔符，在最后一个元素不是必须的
    function parseMetadataField(): MDMField {
        const start = getNodeStart();
        const node = startMetadataLabeledObject(factory.createMetadataField);
        // 简单声明，默认类型为info
        if (match(SyntaxKind.semicolon) || match(SyntaxKind.endKeyword) || match(SyntaxKind.eof)) {
            node.fieldFlag = MDMFieldFlags.info;
            return finishNode(node, start);
        }

        const fieldFlagResult = parseMaybeMetadataFieldType();
        node.fieldFlag = fieldFlagResult.flag;
        // loop
        if (fieldFlagResult.flag === MDMFieldFlags.numericLoop ||
            fieldFlagResult.flag === MDMFieldFlags.categoricalLoop ||
            fieldFlagResult.flag === MDMFieldFlags.grid ||
            fieldFlagResult.flag === MDMFieldFlags.compound) {
            // loop [..]
            if (fieldFlagResult.flag === MDMFieldFlags.numericLoop) {
                node.valueRange = parseMetadataFieldValueRanges();
                // db questions
                if (match(SyntaxKind.mdmDBKeyword)) {
                    return parseMetadataDBQuestions(node);
                }
            }
            // loop {  }
            else {
                node.categories = parseMetadataCategories();
            }
            // fields
            // parseExpected(SyntaxFlag.metadataFieldsKeyword);
            node.class = parseMetadataClass();
            node.asChildren(node.class);
            // row / column / expand / grid
            while (true) {
                if (match(SyntaxKind.mdmRowKeyword)) {
                    node.row = parseTokenNode<Token<SyntaxKind.mdmRowKeyword>>();
                }
                else if (match(SyntaxKind.mdmColumnKeyword)) {
                    node.column = parseTokenNode<Token<SyntaxKind.mdmColumnKeyword>>();
                }
                else if (match(SyntaxKind.mdmExpandKeyword)) {
                    node.expand = parseTokenNode<Token<SyntaxKind.mdmExpandKeyword>>();
                }
                else if (match(SyntaxKind.mdmGridKeyword)) {
                    node.grid = parseTokenNode<Token<SyntaxKind.mdmGridKeyword>>();
                }
                else {
                    break;
                }
            }
        }
        else if (
            (
                fieldFlagResult.flag === MDMFieldFlags.unknown &&
                fieldFlagResult.token.kind === SyntaxKind.mdmFieldsKeyword
            ) ||
            fieldFlagResult.flag === MDMFieldFlags.block) {
            let fieldsKeywordToken: Token<SyntaxKind.mdmFieldsKeyword> | undefined;
            if (fieldFlagResult.flag !== MDMFieldFlags.unknown) {
                fieldsKeywordToken = parseExpectedToken(SyntaxKind.mdmFieldsKeyword);
            }
            // fields
            // parseExpected(SyntaxFlag.openParenthesis);
            node.class = parseMetadataClass(fieldsKeywordToken);
            node.asChildren(node.class);
        }
        // page
        // ( question_name (, question_name)* )
        else if (fieldFlagResult.flag === MDMFieldFlags.page) {
            node.fieldFlagToken = fieldFlagResult.token as Token<SyntaxKind.mdmPageKeyword>;
            const pageFieldsStart = getNodeStart();
            parseExpected(SyntaxKind.openParenthesis);
            const pageFields = parseMetadataObjectList(SyntaxKind.closeParenthesis, () => {
                return parseIdentifierName();
            }, SyntaxKind.comma, false);
            (node as Mutable<MDMPage>).questionNames = createNodeArray(pageFields, pageFieldsStart);
            node.asChildren(...pageFields);
        }
        else {
            // range [ .. ]
            if (match(SyntaxKind.openBracket)) {
                node.valueRange = parseMetadataFieldValueRanges();
            }
            else if (match(SyntaxKind.mdmDBKeyword)) {
                if (!(
                    fieldFlagResult.flag === MDMFieldFlags.text ||
                    fieldFlagResult.flag === MDMFieldFlags.double ||
                    fieldFlagResult.flag === MDMFieldFlags.long ||
                    fieldFlagResult.flag === MDMFieldFlags.date
                )) {
                    raise(errorMessages.invalidMetadataDBType, fieldFlagResult.token, fieldFlagResult.token.text);
                }
                return parseMetadataDBQuestions(node);
            }
            // { category, .. }
            if (match(SyntaxKind.openCurly)) {
                node.categories = parseMetadataCategories();
            }

            if (!matchOne([ SyntaxKind.endKeyword, SyntaxKind.semicolon, SyntaxKind.eof ])) {
                parseMetadataFieldTail(node);
            }
        }

        if (isMetadataFieldToken(fieldFlagResult.token.kind)) {
            node.fieldFlagToken = fieldFlagResult.token as Token<MDMFieldTokenKind>;
        }
        node.asChildren(node.categories, node.fieldFlagToken);

        return finishNode(node, start);
    }

    function parseMetadataDBQuestions(baseField: Mutable<MDMField>): MDMDbQuestions {
        parseExpected(SyntaxKind.mdmDBKeyword);
        const properties = parseMetadataDBQuestionsProperties();
        if (baseField.fieldFlag === MDMFieldFlags.numericLoop) {
            // fields
            // ( <field> (; <field> )* [;] )
            //     [ row | column ]
            //     [ noexpand ]
            // parseExpected(SyntaxFlag.metadataFieldsKeyword);
            baseField.class = parseMetadataClass();

            loop: while (true) {
                switch (currentToken) {
                    case SyntaxKind.mdmRowKeyword:
                        baseField.row = parseTokenNode<Token<SyntaxKind.mdmRowKeyword>>();
                        break;
                    case SyntaxKind.mdmColumnKeyword:
                        baseField.column = parseTokenNode<Token<SyntaxKind.mdmColumnKeyword>>();
                        break;
                    case SyntaxKind.mdmNoExpandKeyword:
                        baseField.noCaseData = parseTokenNode<Token<SyntaxKind.mdmNocaseDataKeyword>>();
                        break;
                    default:
                        break loop;
                }
            }

        }
        else {
            // [ [ range_expression ] ]
            // [ <codes> ]
            // [ expression ("expression_text") ]
            // [ ( initialanswer | defaultanswer ) (date_value) ]
            // [ <axis> ]
            // [ <usage-type> ]
            // [ <helperfields> ]
            // [ nocasedata ]
            // [ unversioned ]
            if (match(SyntaxKind.openBracket)) {
                baseField.valueRange = parseMetadataFieldValueRanges();
            }
            parseMetadataFieldTail(baseField);
        }

        return finishNode(factory.createMetadataDatabaseQuestions(baseField, properties), baseField.start);
    }

    function parseMetadataDocument(language: LocalLanguage, context: MDMUserContextFlags, label: MDMLabelTypeFlags, commentReference?: readonly PPInclude[]): MDMDocument {
        const start = getNodeStart();
        const types: MDMField[] = [];
        const fields: MDMField[] = [];
        const lcl: MDMAreaName[] = [];
        const preprocessor: Preprocessor[] = [];
        const children: Node[] = [];
        let hdata: MDMHierarchicalView | undefined;

        if (commentReference) {
            preprocessor.push(...commentReference);
        }

        scanner.setContext(ScannerContextType.metadata);

        while (true) {
            if (match(SyntaxKind.eof) || (match(SyntaxKind.endKeyword) && lookAhead(() => nextIs(SyntaxKind.metadataKeyword)))) {
                break;
            }
            // metadata 文件允许使用预处理器
            else if (matchOne([
                SyntaxKind.ppDefineKeyword,
                SyntaxKind.ppIfKeyword,
                SyntaxKind.ppIfDefKeyword,
                SyntaxKind.ppIfNDefKeyword,
                SyntaxKind.ppErrorKeyword,
                SyntaxKind.ppLineKeyword,
                SyntaxKind.ppUndefKeyword,
                SyntaxKind.ppIncludeKeyword,
            ])) {
                switch (currentToken) {
                    case SyntaxKind.ppDefineKeyword:
                        const define = parsePreprocessorDefineStatement();
                        children.push(define);
                        preprocessor.push(define);
                        break;
                    case SyntaxKind.ppErrorKeyword:
                        const error = parsePreprocessorErrorStatement();
                        children.push(error);
                        preprocessor.push(error);
                        break;
                    case SyntaxKind.ppIfKeyword:
                        const preIf = parsePreprocessorIfStatement();
                        children.push(preIf);
                        preprocessor.push(preIf);
                        break;
                    case SyntaxKind.ppIfDefKeyword:
                        const preIfD = parsePreprocessorIfDefStatement();
                        children.push(preIfD);
                        preprocessor.push(preIfD);
                        break;
                    case SyntaxKind.ppIfNDefKeyword:
                        const preIfN = parsePreprocessorIfNDefStatement();
                        children.push(preIfN);
                        preprocessor.push(preIfN);
                        break;
                    case SyntaxKind.ppLineKeyword:
                        const preLine = parsePreprocessorLineStatement();
                        children.push(preLine);
                        preprocessor.push(preLine);
                        break;
                    case SyntaxKind.ppUndefKeyword:
                        const undef = parsePreprocessorUndefStatement();
                        children.push(undef);
                        preprocessor.push(undef);
                        break;
                    case SyntaxKind.ppIncludeKeyword:
                        const inc = parsePreprocessorIncludeStatement();
                        children.push(inc);
                        preprocessor.push(inc);
                        break;
                }
            }
            else if (isIdentifierOrReservedWord(currentToken) || match(SyntaxKind.stringLiteral)) {
                if (lookAhead(() => nextIs(SyntaxKind.mdmLCLKeyword))) {
                    const area = parseMetadataAreaName();
                    lcl.push(area);
                    children.push(area);
                }
                else {
                    const field = parseMetadataField();
                    if (field.name.text.toLowerCase() === "hdata") {
                        hdata = factory.createMetadataHierarchicalView(field);
                    }
                    else if (field.fieldFlag === MDMFieldFlags.define) {
                        types.push(field);
                    }
                    else {
                        fields.push(field);
                    }
                    children.push(field);
                }
                const semi = parseOptionalToken<SyntaxKind.semicolon>(SyntaxKind.semicolon);
                if (match(SyntaxKind.endKeyword) && !semi) {
                    raise(errorMessages.unexpectedToken, ";");
                }
            }
            else {
                raise(errorMessages.syntaxError, scanner.getTokenText());
                next();
            }
        }

        scanner.setContext(ScannerContextType.normal);

        const metadata = factory.createMetadataDocument(language, context, label, types, fields, hdata, lcl, preprocessor);
        metadata.asChildren(...children);
        return finishNode(metadata, start);
    }

}

export namespace PreprocessorParser {

    const scanner = createScanner();
    let currentToken: SyntaxKind = SyntaxKind.eof;

    function match(flag: SyntaxKind) {
        return currentToken === flag;
    }

    function next() {
        return currentToken = scanner.scan();
    }

    function nextPreprocessor() {
        while (!match(SyntaxKind.ppIncludeKeyword) && !match(SyntaxKind.eof)) {
            currentToken = scanner.scan();
        }
        return currentToken;
    }

    function lookAhead<T>(callback: () => T): T {
        let cur = currentToken;
        let result = scanner.lookAhead(callback);
        currentToken = cur;
        return result;
    }

    interface PreprocessorParseResult {
        readonly commentReferences: readonly FileDirective[];
        readonly nodes: readonly PPInclude[];
    }

    export function parse(fsPath: string, initialText: string, startPos?: number): PreprocessorParseResult {
        const nodes: PPInclude[] = [];
        const commentReferences: FileDirective[] = [];
        scanner.setText(initialText, startPos);
        next();

        if (startPos === undefined || startPos === 0) {
            const headerComments = scanner.getComments();
            for (const comment of headerComments) {
                if (comment.comments.length > 1) {
                    continue;
                }
                let commentText = comment.comments[0];
                let commentStart = comment.start;
                let info = getCommentReference(commentText);
                if (!info) {
                    continue;
                }
                if (typeof info === "string") {
                    commentReferences.push({
                        fileName: info,
                        value: "",
                        span: {
                            start: commentStart + commentText.indexOf(info),
                            length: info.length
                        }
                    });
                }
                else {
                    commentReferences.push({
                        fileName: info.fileName,
                        value: info.value,
                        span: {
                            start: commentStart + info.span.start,
                            length: info.span.length
                        }
                    });
                }
            }
        }

        while (true) {
            if (match(SyntaxKind.eof)) {
                break;
            }
            if (match(SyntaxKind.ppIncludeKeyword)) {
                const start = scanner.getTokenStart();
                const context = scanner.saveState().context;
                scanner.setContext(ScannerContextType.preprocessor);
                next();
                if (match(SyntaxKind.stringLiteral) && lookAhead(() => {
                    next();
                    return scanner.hasPrecedingLinebreak();
                })) {
                    const stringStart = scanner.getTokenStart();
                    next();
                    const stringEnd = scanner.getStartPos();
                    let text = removeStringQuotation(scanner.getTokenText(stringStart, stringEnd));
                    const literal = factory.createStringLiteral(
                        text,
                        !!(scanner.getTokenFlag() & TokenFlags.multiLineString) ? LiteralType.multiLineString : LiteralType.singleLineString
                    );
                    setTextRangeStartEnd(literal, stringStart, stringEnd);
                    const node = factory.createPreprocessorIncludeStatement(
                        literal,
                        resolve(dirname(fsPath), literal.text)
                    );
                    setTextRangeStartEnd(node, start, stringEnd);
                    nodes.push(node);
                }
                scanner.setContext(context);
            }
            nextPreprocessor();
        }
        return { commentReferences, nodes };
    }

}
